mirror of
https://github.com/reactjs/react.dev.git
synced 2026-02-21 19:31:57 +00:00
Add more information about event and property binding on custom elements (#7939)
Co-authored-by: Sebastian "Sebbie" Silbermann <silbermann.sebastian@gmail.com>
This commit is contained in:
@@ -162,23 +162,137 @@ Similar to the [DOM standard,](https://developer.mozilla.org/en-US/docs/Web/API/
|
||||
|
||||
### Custom HTML elements {/*custom-html-elements*/}
|
||||
|
||||
If you render a tag with a dash, like `<my-element>`, React will assume you want to render a [custom HTML element.](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) In React, rendering custom elements works differently from rendering built-in browser tags:
|
||||
|
||||
- All custom element props are serialized to strings and are always set using attributes.
|
||||
- Custom elements accept `class` rather than `className`, and `for` rather than `htmlFor`.
|
||||
If you render a tag with a dash, like `<my-element>`, React will assume you want to render a [custom HTML element.](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements)
|
||||
|
||||
If you render a built-in browser HTML element with an [`is`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/is) attribute, it will also be treated as a custom element.
|
||||
|
||||
#### Setting values on custom elements {/*attributes-vs-properties*/}
|
||||
|
||||
Custom elements have two methods of passing data into them:
|
||||
|
||||
1) Attributes: Which are displayed in markup and can only be set to string values
|
||||
2) Properties: Which are not displayed in markup and can be set to arbitrary JavaScript values
|
||||
|
||||
By default, React will pass values bound in JSX as attributes:
|
||||
|
||||
```jsx
|
||||
<my-element value="Hello, world!"></my-element>
|
||||
```
|
||||
|
||||
Non-string JavaScript values passed to custom elements will be serialized by default:
|
||||
|
||||
```jsx
|
||||
// Will be passed as `"1,2,3"` as the output of `[1,2,3].toString()`
|
||||
<my-element value={[1,2,3]}></my-element>
|
||||
```
|
||||
|
||||
React will, however, recognize an custom element's property as one that it may pass arbitrary values to if the property name shows up on the class during construction:
|
||||
|
||||
<Sandpack>
|
||||
|
||||
```js src/index.js hidden
|
||||
import {MyElement} from './MyElement.js';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import {App} from "./App.js";
|
||||
|
||||
customElements.define('my-element', MyElement);
|
||||
|
||||
const root = createRoot(document.getElementById('root'))
|
||||
root.render(<App />);
|
||||
```
|
||||
|
||||
```js src/MyElement.js active
|
||||
export class MyElement extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
// The value here will be overwritten by React
|
||||
// when initialized as an element
|
||||
this.value = undefined;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.innerHTML = this.value.join(", ");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js src/App.js
|
||||
export function App() {
|
||||
return <my-element value={[1,2,3]}></my-element>
|
||||
}
|
||||
```
|
||||
|
||||
</Sandpack>
|
||||
|
||||
#### Listening for events on custom elements {/*custom-element-events*/}
|
||||
|
||||
A common pattern when using custom elements is that they may dispatch [`CustomEvent`s](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) rather than accept a function to call when an event occur. You can listen for these events using an `on` prefix when binding to the event via JSX.
|
||||
|
||||
<Sandpack>
|
||||
|
||||
```js src/index.js hidden
|
||||
import {MyElement} from './MyElement.js';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import {App} from "./App.js";
|
||||
|
||||
customElements.define('my-element', MyElement);
|
||||
|
||||
const root = createRoot(document.getElementById('root'))
|
||||
root.render(<App />);
|
||||
```
|
||||
|
||||
```javascript src/MyElement.js
|
||||
export class MyElement extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.test = undefined;
|
||||
this.emitEvent = this._emitEvent.bind(this);
|
||||
}
|
||||
|
||||
_emitEvent() {
|
||||
const event = new CustomEvent('speak', {
|
||||
detail: {
|
||||
message: 'Hello, world!',
|
||||
},
|
||||
});
|
||||
this.dispatchEvent(event);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.el = document.createElement('button');
|
||||
this.el.innerText = 'Say hi';
|
||||
this.el.addEventListener('click', this.emitEvent);
|
||||
this.appendChild(this.el);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.el.removeEventListener('click', this.emitEvent);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```jsx src/App.js active
|
||||
export function App() {
|
||||
return (
|
||||
<my-element
|
||||
onspeak={e => console.log(e.detail.message)}
|
||||
></my-element>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
</Sandpack>
|
||||
|
||||
<Note>
|
||||
|
||||
[A future version of React will include more comprehensive support for custom elements.](https://github.com/facebook/react/issues/11347#issuecomment-1122275286)
|
||||
Events are case-sensitive and support dashes (`-`). Preserve the casing of the event and include all dashes when listening for custom element's events:
|
||||
|
||||
You can try it by upgrading React packages to the most recent experimental version:
|
||||
|
||||
- `react@experimental`
|
||||
- `react-dom@experimental`
|
||||
|
||||
Experimental versions of React may contain bugs. Don't use them in production.
|
||||
```jsx
|
||||
// Listens for `say-hi` events
|
||||
<my-element onsay-hi={console.log}></my-element>
|
||||
// Listens for `sayHi` events
|
||||
<my-element onsayHi={console.log}></my-element>
|
||||
```
|
||||
|
||||
</Note>
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user