@irozon/design-system-react
v0.7.0
Published
Canonical React components for the Irozon Design System — thin, accessible wrappers over @irozon/design-system's framework-neutral iz-* CSS. No independent visual styling of its own; the CSS package stays the single source of truth for how these look.
Maintainers
Readme
@irozon/design-system-react
React components for the Irozon Design System, built on the same
framework-neutral CSS as @irozon/design-system.
Install
npm install @irozon/design-system-react @irozon/design-systemQuick start
import "@irozon/design-system/irozon.css";
import { Button } from "@irozon/design-system-react";
export function SaveButton() {
return <Button variant="primary">Save</Button>;
}Import the CSS once in your application entry point. The React package ships
components, while @irozon/design-system remains the source of their visual
styles.
What it provides
- Typed React components for the Irozon Design System's shared UI.
- Accessible markup and state wiring for the underlying
iz-*CSS classes. - Native element props alongside the documented design-system props.
- No business logic or application-specific state.
For example, fields compose naturally from the exported components:
import { FormField, Input } from "@irozon/design-system-react";
export function EmailField() {
return (
<FormField label="Email" hint="We'll never share it">
<Input type="email" name="email" />
</FormField>
);
}Full documentation
Visit the Irozon Design System documentation for React usage, component behavior, foundations, tokens, examples, and accessibility guidance.
Related Irozon packages
@irozon/design-tokens Design foundations and CSS variables
↓
@irozon/design-system Framework-neutral component CSS
↓
@irozon/design-system-react React components using the same system ← you are here@irozon/design-system-react depends on @irozon/design-system, but install
both packages because your app imports the CSS package directly.
Components
| Component | Wraps |
| --- | --- |
| Button | .iz-button |
| Card | .iz-card |
| SignatureCTA | .iz-signature-cta |
| Loader | .iz-loader |
| Input, Textarea | .iz-input, .iz-textarea |
| Select | .iz-select-wrap / .iz-select |
| Checkbox | .iz-checkbox |
| FormField | .iz-field |
| Dialog, DialogHeader, DialogBody, DialogFooter | .iz-dialog |
| ConfirmDialog | composes Dialog + Button |
| Toast, ToastRegion | .iz-toast, .iz-toast-region |
| ThemeToggle | .iz-theme-toggle |
| Nav, NavGroup, NavItem | .iz-nav, .iz-nav-group, .iz-nav-item |
| Tabs, TabPanel | .iz-tabs, .iz-tab, .iz-tab-panel |
For side Sheets, pass variant="sheet". The default size keeps the narrow
panel; size="large" uses about 80% of the desktop viewport. Both sizes use
the available screen width on small viewports. The native <dialog> retains
focus management, Escape handling, and backdrop behavior.
Checkbox
Checkbox wraps a native <input type="checkbox">, preserving browser
keyboard behavior, form submission, controlled/uncontrolled props, and refs.
Use it for multi-selection; use Switch for an on/off setting.
import { Checkbox } from "@irozon/design-system-react";
<Checkbox
name="company"
value="acme"
label="Acme AB"
checked={selected}
onChange={(event) => setSelected(event.currentTarget.checked)}
/>
<Checkbox aria-label="Select Acme AB" />
<Checkbox label="Email updates" description="Monthly product news." />Use indeterminate for a mixed select-all state. Keep checked as the
authoritative selection value and update both from your selection model:
<Checkbox
label="Select all companies"
checked={allSelected}
indeterminate={someSelected && !allSelected}
onChange={(event) => selectAll(event.currentTarget.checked)}
/>The mixed state is applied to the native input's indeterminate property,
which is a DOM property rather than a serializable HTML attribute.
Card
Card defaults to a static <div>. Set interactive to opt into the
canonical hover/focus treatment, and choose an anchor, button, or router link
with as so navigation and actions keep native semantics:
import { Card } from "@irozon/design-system-react";
<Card>Grouped details</Card>
<Card as="a" href="/services/example" interactive>
Service details
</Card>
<Card as="button" type="button" interactive>
Choose this option
</Card>The component only maps props to .iz-card and data-* attributes. Padding,
variants, colors, focus, hover, theme, and reduced-motion behavior stay in
@irozon/design-system CSS.
Signature CTA
SignatureCTA renders the canonical .iz-signature-cta structure and uses
the same framework-neutral CSS as standalone HTML. It renders an anchor by
default; choose a button for an action, or pass a router link component through
as to retain client-side navigation:
import { Link } from "react-router-dom";
import { SignatureCTA } from "@irozon/design-system-react";
<SignatureCTA href="/contact">Get in touch</SignatureCTA>
<SignatureCTA as="button" type="submit" onClick={submitForm}>
Send message
</SignatureCTA>
<SignatureCTA as={Link} to="/contact">
Get in touch
</SignatureCTA>Props for the rendered element are inferred from as, including its
accessibility, event, and navigation props. The CTA owns its decorative
three-dot motif in CSS; consumers provide the semantic label only.
Tabs/TabPanel implement the full WAI-ARIA Tabs pattern (automatic
activation): a roving tabindex so only the selected tab sits in the page's Tab
order, ArrowLeft/ArrowRight to move between tabs, Home/End to jump to the
first/last, and a plain click. Pair them via a shared idPrefix:
import { useState } from "react";
import { Tabs, TabPanel } from "@irozon/design-system-react";
function Example() {
const [tab, setTab] = useState("overview");
return (
<>
<Tabs
idPrefix="example"
aria-label="Example sections"
value={tab}
onValueChange={setTab}
tabs={[
{ value: "overview", label: "Overview" },
{ value: "details", label: "Details" },
]}
/>
<TabPanel idPrefix="example" value="overview" activeValue={tab}>
Overview content
</TabPanel>
<TabPanel idPrefix="example" value="details" activeValue={tab}>
Details content
</TabPanel>
</>
);
}The component documentation includes live examples and React usage. TypeScript declarations in the package provide the complete prop types.
Advanced usage
Routed navigation
NavItem renders a plain <a> by default. Pass your router's own Link
component via as to get real client-side navigation while keeping this
component's markup/classes/accessibility:
import { Link } from "@tanstack/react-router";
import { NavItem } from "@irozon/design-system-react";
<NavItem as={Link} to="/invoice" active={pathname === "/invoice"}>
Invoices
</NavItem>;ThemeToggle direction
import { ThemeToggle, type ThemeToggleProps } from "@irozon/design-system-react";
<ThemeToggle isDark={isDark} onToggle={toggleTheme} />;
<ThemeToggle isDark={isDark} onToggle={toggleTheme} direction="vertical" />;
<ThemeToggle isDark={isDark} onToggle={toggleTheme} direction="horizontal" />;direction?: "vertical" | "horizontal" defaults to "vertical". Vertical
reveals Light above Dark; horizontal reveals Light on the left and Dark on
the right. Both keep the centered resting dot, 44×44 hit area, colors,
keyboard activation, focus ring, and reduced-motion behavior. The horizontal
track is 38×20 instead of 20×38. Use the matching CSS package containing
data-direction="horizontal" support. isDark and onToggle remain required;
the consuming application continues to own theme state and persistence.
ThemeToggleProps is exported through the existing package entry point.
Canonical API
Prop names and values match the CSS package's own vocabulary exactly —
variant="destructive", not variant="danger"; size="small", not
size="sm". Product apps migrating from a local wrapper should adopt
these names at the call sites, not keep a permanent translation layer.
Package boundaries
- No CSS of its own — if a component looks wrong, the fix belongs in
@irozon/design-system, not here. - No app state: toast list contents, dialog open/closed state, theme persistence, form validation — all owned by the consuming app.
- No business/domain logic — nothing here knows what an "invoice" or a "proposal" is.
React and React DOM >=18.0.0 are peer dependencies and are not bundled.
Release notes
0.7.0
- Add the forwarded-ref
Checkboxcomponent with native checked, disabled, form, and indeterminate behavior. - Require
@irozon/design-system@^0.10.0for the shared.iz-checkboxstyles.
0.6.0
- Add optional ThemeToggle
direction="vertical" | "horizontal"; vertical remains the default. - Require
@irozon/design-system@^0.9.0for the 38px track and shared 500ms spring movement. - Preserve controlled theme state, accessible labels, keyboard activation and reduced motion.
Versioning and compatibility
This package is currently in 0.x and uses the component vocabulary from
@irozon/design-system. Minor releases may introduce API changes before
1.0.0; check the release notes when upgrading.
License
MIT © Irozon AB
