@gtmi/strix-react
v0.5.0
Published
Strix: AI-native React design system
Keywords
Readme
Installation
npm install @gtmi/strix-reactReact is the only peer dependency — 18 or newer, with react-dom to match. Tailwind CSS and Base UI
come with the package, so there is nothing else to add.
Requirements
Strix is styled with Tailwind CSS v4 and ships its token layer as source, so Tailwind has to see it. Add this once, in the stylesheet Tailwind processes:
@import 'tailwindcss';
@import '@gtmi/strix-react/tokens.css';Without that import the components render unstyled — every utility they use is generated from those
tokens, so nothing resolves. Tailwind has to come first: tokens.css does not import
tailwindcss itself and its @theme block extends Tailwind's, so reversing the two produces no
error and silently missing utilities.
You do not need an @source line. Tailwind v4 skips node_modules when detecting content, so
Strix's compiled classes would never be generated — tokens.css therefore declares the @source
itself. An @source resolves relative to the stylesheet that declares it, which makes that one line
correct from any layout: pnpm's nested store, a monorepo at any depth, hoisted or not.
React Server Components
Every entry ships 'use client' except ., ./cn and ./tokens, so any component can be rendered
straight from a server component and cn() stays callable during a server render. On the Next.js App
Router there is nothing to configure — no transpilePackages, no tsconfig paths, no PostCSS
plugin.
Testing
Strix is ESM-only. Vitest needs nothing. Jest needs a .js transform and a
transformIgnorePatterns carve-out — the exact config, and the rest of the integration surface, is
in docs/CONSUMING.md.
Usage
Components
import { Button } from '@gtmi/strix-react/button';
import { Card } from '@gtmi/strix-react/card';
export function App() {
return (
<Card heading="Hello">
<Button>Click me</Button>
</Card>
);
}Utilities
import { cn } from '@gtmi/strix-react/cn';
const className = cn('px-4', { 'py-2': true });Themes
The tokens define both themes. ThemeProvider stamps the active one onto a data-theme attribute,
and useTheme reads or changes it:
import { ThemeProvider, useTheme } from '@gtmi/strix-react/theme';
export function App() {
return (
<ThemeProvider initialTheme="dark">
<YourApp />
</ThemeProvider>
);
}ThemeProvider stamps tokens but paints no background, so give your own root a surface —
className="bg-surface-base" — or dark text will land on a white page.
Dark is the default. The dark values are declared under :root as well as
[data-theme="dark"], so an app that renders no provider and sets no attribute is already dark.
Light is opt-in: initialTheme="light", or data-theme="light" on your root element.
prefers-color-scheme is deliberately never consulted — read it yourself and pass the result as
initialTheme if you want to follow the OS.
Set color-scheme: dark on your own root too, or native UI (scrollbars, form controls, the caret)
stays light against a dark page.
Icons
All 340 icons are individually importable, so a bundler only ever sees the ones you use:
import { PhoneIcon } from '@gtmi/strix-react/icons/phone';Patterns
Larger compositions live under patterns/:
import { ChatLog } from '@gtmi/strix-react/patterns/chat-log';
import { MetricList } from '@gtmi/strix-react/patterns/metric-list';Accessibility
Every component is measured rather than assumed. Contrast is asserted from each component's own
class output in both themes, prefers-reduced-motion is honoured throughout, and the browser
harnesses check the things axe cannot: focus trapping, forced-colours mode, and reflow at 320 CSS
pixels. The current state is 510 story renders with no axe violations and 61 keyboard checks with no
failures.
Development
This package lives in a monorepo. See the repository README for the full workflow; the short version:
pnpm install
pnpm build
pnpm test
pnpm storybookLicense
MIT
