React
Typed React components generated from Tanrei's Web Components.
@tanrei/react wraps each custom element from @tanrei/web in a real React component with typed props and event handlers. The wrappers are generated from the custom elements manifest, so they always match the elements they wrap.
Prerelease
0.1.0-next.0 is published to npm under the dist-tag next: until 0.1.0, install @tanrei/react@next and @tanrei/web@next. During the 0.x prereleases backward compatibility is not kept: any prerelease may break anything, with no deprecation period first, and its changeset says what broke.
React 18 or later is required.
npm install @tanrei/react @tanrei/webTo use the source as it stands on main, do as for the Web package (Git, Node 22.22 or later, pnpm 12): build both packages in a clone of the repository and pack them,
git clone https://github.com/chnotchy/tanrei.git
cd tanrei
pnpm install
pnpm --filter @tanrei/web --filter @tanrei/react build
pnpm --filter @tanrei/web --filter @tanrei/react pack --pack-destination ../tanrei-packagesthen install both packed files in your project with one command, so that the React package finds the Web package beside it:
npm install path/to/tanrei-packages/tanrei-web-*.tgz path/to/tanrei-packages/tanrei-react-*.tgzLoad the stylesheets once, before the components render: tanrei.css is the base of the page, the tokens and every other stylesheet of the package in one file. To load them one by one, see the Web guide.
import '@tanrei/web/tanrei.css';
import '@tanrei/web/words/en';
import { Button } from '@tanrei/react';
export function Toolbar({ onDeploy }: { onDeploy: () => void }) {
return (
<>
<Button variant="filled" onClick={onDeploy}>
Deploy
</Button>
<Button variant="text" size="small" disabled>
Roll back
</Button>
</>
);
}Props carry the same names as the element’s attributes (variant, size, disabled). Events are ordinary React handlers. An element’s own event is on and the event’s name in camel case, as React names its own (onKeyDown): a navigation drawer fires expandedchange, and you listen with onExpandedChange.
@tanrei/web/words/en gives a word in plain English for every label and message the components draw or say, such as a required tag’s or a close button’s; leave it out and give your own with setWords() from @tanrei/react. See Words.
The package has an entry for each design system Tanrei ships, so that your editor offers, and the type check accepts, only what your system has:
| Entry | What it exports |
|---|---|
@tanrei/react |
The components of the default system, Tanrei. The FAB menu, which lives in the m3-like layer, and the segmented button, which Tanrei leaves out, are not in it, and a variant Tanrei leaves out is not a value of the prop: <TextField variant="outlined"> does not type-check |
@tanrei/react/m3-like, @tanrei/react/m3-expressive-like, @tanrei/react/cupertino |
The components of that preset, with its variants |
@tanrei/react/advanced |
The advanced components, the building blocks of others: TextInput, ModalLayer, Combobox and the rest. A product usually writes the component built from one — TextField, Dialog, ComboboxField |
@tanrei/react/all |
Every component, whichever system has it: for a design system of your own, and for building one |
import '@tanrei/web/tokens.css';
import '@tanrei/web/systems/m3-like.css';
import { FabMenu, FabMenuItem, TextField } from '@tanrei/react/m3-like';A component is the same in every entry, so a bundler still keeps only what you import. Every entry also exports setWords, missingWords and the TanreiEvent type. The entries are generated from each system’s components manifest, @tanrei/web/systems/<id>.components.json, which names the entry of each component (react.import); the manifest of your own system, which tanrei build writes, names @tanrei/react/all.
The components render a custom element tag on the server and upgrade in the browser. In frameworks with a server/client split, import the entry you use from a client component so the element definitions are registered in the browser.
Note
Theme, contrast, tokens and fonts work exactly as described in the Web guide; the React package adds nothing of its own on top.