cinder-react
v1.0.1
Published
React bindings for cinder-ui, generated from its custom elements manifest.
Readme
cinder-react
React bindings for cinder-ui, the Cinder design
system from the book Web Components with Lit. One typed React component per Cinder element,
generated from Cinder's custom elements manifest with
@lit/react.
Why a wrapper
On React 18 and earlier, a custom element in JSX gets every prop as a string attribute and
has no way to listen for custom events — so value={obj} and onCnChange don't work. This
package fixes both: every prop is set as a property, and every cn-* event is a typed
on… handler.
On React 19+ custom elements work natively; the wrapper is optional but still gives you
property-always binding and handlers typed from the manifest (e.detail.value is a string,
no cast).
Install
npm install cinder-react cinder-ui react react-domreact and react-dom are peer dependencies (>=18).
Use
import { CnButton, CnTextField } from 'cinder-react';
export function SignUp() {
const [email, setEmail] = useState('');
return (
<>
<CnTextField label="Email" type="email" required value={email}
onCnChange={(e) => setEmail(e.detail.value)} />
<CnButton variant="primary">Save</CnButton>
</>
);
}Link the theme once in your document (cinder-ui/themes/tokens.css) — the components are
the same custom elements underneath, so theming, form participation, and accessibility all
work exactly as documented for cinder-ui.
Components
CnButton, CnCheckbox, CnDialog, CnField, CnIcon, CnSelect, CnSpinner,
CnTextField, CnThemeProvider, CnToast, CnTooltip — one for each cn-* element.
Event handlers follow the element's events: cn-change → onCnChange, cn-close → onCnClose,
and so on, each typed with that event's detail.
Regenerating
The wrappers are generated, not hand-written. npm run build reads
cinder-ui/custom-elements.json and emits one file per component, then compiles them —
re-running it is the whole update process when Cinder changes.
License
MIT © 2026 Sandeep Patel
