@gunaseelank04/web-components
v0.4.1
Published
Framework-agnostic Web Components built with React
Maintainers
Readme
@gunaseelank04/web-components
Framework-agnostic Web Components, built with React and compiled to native
Custom Elements via @r2wc/react-to-web-component.
Components are usable in any framework (or none) as plain HTML tags, while still being authored, tested, and developed as ordinary React components.
Development
npm install
npm run dev # opens index.html demo with live custom elements
npm run build # bundles dist/ (ESM + CJS) and generates .d.ts
npm run typecheckUsage (once published)
npm install @gunaseelank04/web-components react react-dom<script type="module">
import "@gunaseelank04/web-components";
</script>
<wc-button label="Click me" variant="primary"></wc-button>
<script>
document.querySelector("wc-button").onClick = () => console.log("clicked");
</script>Or use the underlying React component directly in a React app:
import { Button } from "@gunaseelank04/web-components";
<Button label="Click me" onClick={() => console.log("clicked")} />;DataTable (<wc-data-table>)
Built on TanStack Table. Ships self-contained:
it bundles @tanstack/react-table, @dnd-kit/*, @mantine/core, and
@tabler/icons-react, and wraps itself in its own internal MantineProvider
and injected stylesheet, so it renders correctly on a page that has no
Mantine setup at all.
All props must be set as JS properties, not HTML attributes. Column
defs and several other props carry render/callback functions, which cannot
survive an HTML-attribute string round-trip — <wc-data-table columns="...">
will not work.
<wc-data-table id="table"></wc-data-table>
<script type="module">
import "@gunaseelank04/web-components";
const table = document.getElementById("table");
table.columns = [
{ accessorKey: "name", header: "Name" },
{ accessorKey: "score", header: "Score" },
];
table.data = [
{ name: "Ada Lovelace", score: 98 },
{ name: "Alan Turing", score: 99 },
];
table.enableSorting = true;
table.numericColumns = ["score"];
</script>Or directly in React:
import { DataTable } from "@gunaseelank04/web-components";
<DataTable
columns={[{ accessorKey: "name", header: "Name" }]}
data={[{ name: "Ada Lovelace" }]}
enableSorting
/>;See src/components/Table/types.ts for the full DataTableProps list
(sorting, pagination, row selection, column drag-reorder/resize, expansion,
inline filters, sticky columns).
Adding a new component
Two supported patterns, depending on whether the component's props are plain strings/numbers/booleans or carry functions/objects:
Simple props (e.g. Button) — use r2wc, which reflects props to/from
HTML attributes:
- Create
src/components/MyThing/MyThing.tsx(+index.tsre-export). - Register it in
src/elements/register.tsviar2wc(MyThing, { props: {...} }). Use"method"(not"function") for callback props —"function"reflects the handler to an attribute viafn.name, which breaks for any named function. - Export the React component and the element from
src/index.ts.
Rich props (e.g. DataTable) — props include functions or objects
containing functions (column defs, row-render callbacks, etc.). r2wc's
"json" transform round-trips through JSON.stringify/parse, which
silently drops function values. Use createPropertyElement from
src/utils/propertyElement.tsx instead: it sets props as plain JS
properties with no attribute reflection at all. See wc-data-table's
registration in src/elements/register.ts for the pattern.
Publishing
npm run build
npm publish --access publicreact and react-dom are peer dependencies — consumers must have them
installed. The custom element wrapper mounts its own React root internally,
so no React setup is required on the consumer's page for the custom-element
usage to work.
Gotcha: boolean attributes
@r2wc/core's "boolean" prop type does not use native HTML
presence-only semantics. A bare disabled attribute (no value) parses as
false. Always write an explicit value:
<!-- wrong: parses as disabled=false -->
<wc-button disabled></wc-button>
<!-- correct -->
<wc-button disabled="true"></wc-button>