1.1.1 • Published 2 months ago
better-react-web-component v1.1.1
Better React Web Component
Wrapper for React (v18.x) Component to CustomElement that magically just works and is type safe with Typescript!
- Small. About 1kB (minified and gzipped). Zero dependencies.
- Simple. Each component interface is defined with strict types.
- Good TypeScript support.
import { createCustomElement, InferProps, optional } from 'better-react-web-component'
// Define custom component interface
HelloComponent.types = {
name: optional.string,
}
// Infer typescript types
type ComponentProps = InferProps<typeof HelloComponent.types>
// Defined component
function HelloComponent({ name = "unknown" }: ComponentProps) {
return (
<h1>Hello {name}!</h1>
)
}
// Create and register custom component
customElements.define(
"hello-component",
createCustomElement(HelloComponent, "shadowRoot"),
)
Usage in html:
<hello-component name="World" />
Install
npm install better-react-web-component
Guide
Define attributes
Attributes are defined on component types
object.
Note Attribute names defined here are case-insensitive as they are in HTML spec! Hence the below can be used as
<component name="..." />
or<component nAmE="..." />
.
MyReactComponent.types = {
name: optional.string,
requiredName: required.string,
}
Supported prop types:
- String:
-
optional.string
-required.string
- Number:
-
optional.number
-required.number
- Boolean:
-
optional.boolean
-required.boolean
- Json (parses attribute with JSON.parse):
-
optional.json
-required.json
- Function:
-
optional.event
-required.event
Define default values
Default values are defined on react component itself.
function MyReactComponent({
requiredName,
name = "unknown",
}: InferProps<typeof MyReactComponent.types>) {
...
}
Handle events
This package also supports custom events to be defined.
Note Event names defined here are CASE-SENSITIVE so we lowercase them and remove leading
"on"
to match other event names!
import { createCustomElement, InferProps, optional } from 'better-react-web-component'
import { useState } from 'react'
InputName.types = {
name: optional.string,
onNameChange: optional.func, // Event name must start with "on" and will be lowercase in html land
}
function InputName({
name = 'unknown',
onNameChange,
}: InferProps<typeof InputName.types>) {
const [localName, setLocalName] = useState(name)
return (
<input
value={localName}
onChange={(e) => {
setLocalName(e.target.value)
onNameChange?.({ detail: e.target.value }) // Trigger custom event here if it's defined
}}
/>
)
}
customElements.define('input-name', createCustomElement(InputName))
At the same time in html land:
<input-name name="World" />
<script>
const inputNameEl = document.querySelector('input-name');
// Note that event name is ALWAYS lowercase without `on` in front of it
inputNameEl.addEventListener('namechange', (e) => {
console.log(e.detail);
});
</script>