A strict, accessible design system library for internal applications.
Frey UI targets ES2016+ and supports all modern evergreen browsers:
- Chrome / Edge 80+
- Firefox 78+
- Safari 14+
Frey UI is built with WCAG 2.1 AA compliance as a goal:
- All interactive components use semantic HTML (
button,input,label). - Non-native interactive elements receive
role,tabIndex, and keyboard handlers automatically. - Every form control requires a
labelprop; labels can be visually hidden withhideLabel. - Focus is always visible (
:focus-visiblestyles on every interactive component). - Disabled states are functional, not just visual.
Automated accessibility checks run via jest-axe in unit tests and the @storybook/addon-a11y panel in Storybook.
pnpm add frey-ui
# OR
npm install frey-uiImport the stylesheet once in your app's root file (e.g. App.tsx or layout.tsx).
This file includes all component styles and the default theme variables — it is required.
import 'frey-ui/style.css';import { Chip, Switch, ThemeProvider } from 'frey-ui';
function App() {
return (
<ThemeProvider theme='light'>
<Chip label='Status' variant='outlined' />
<Switch label='Enable Dark Mode' />
</ThemeProvider>
);
}A polymorphic label / action component.
| Prop | Type | Default | Description |
|---|---|---|---|
label |
string |
— | Required. Text content of the chip. |
variant |
'default' | 'outlined' |
'default' |
Visual style variant. |
as |
'button' | 'div' | 'span' | 'a' |
'span' (or 'button' when onClick is provided) |
HTML element to render. |
onClick |
MouseEventHandler |
— | Click handler. When provided, the chip renders as a button by default. |
className |
string |
— | Additional CSS class. |
style |
CSSProperties |
— | Inline styles / CSS variable overrides. |
ref |
Ref |
— | Forwarded ref to the underlying element. |
Non-native interactive chips (as="div" with onClick) automatically receive role="button", tabIndex={0}, and keyboard support (Enter / Space).
An accessible toggle switch built on a native <input type="checkbox" role="switch">.
| Prop | Type | Default | Description |
|---|---|---|---|
label |
string |
— | Required. Accessible label text. |
hideLabel |
boolean |
false |
Visually hide the label (remains accessible to screen readers). |
size |
'sm' | 'md' | 'lg' |
'md' |
Size variant. |
checked |
boolean |
— | Controlled checked state. |
defaultChecked |
boolean |
— | Initial checked state (uncontrolled). |
disabled |
boolean |
false |
Disables the switch. |
onChange |
ChangeEventHandler<HTMLInputElement> |
— | Change handler. |
className |
string |
— | Additional CSS class. |
style |
CSSProperties |
— | Inline styles / CSS variable overrides. |
ref |
Ref<HTMLInputElement> |
— | Forwarded ref to the native input. |
All standard <input> attributes (except type, size) are also supported and spread onto the underlying element.
Wraps children with theme CSS variables.
| Prop | Type | Default | Description |
|---|---|---|---|
children |
ReactNode |
— | Required. Child content. |
theme |
'light' | 'dark' |
'light' |
Active theme. |
id |
string |
— | Container id. |
className |
string |
— | Additional CSS class. |
style |
CSSProperties |
— | Inline styles. |
Override component visuals with CSS custom properties on any ancestor:
.my-switch {
--switch-track-active: #22c55e;
--switch-track-inactive: #94a3b8;
--switch-focus-ring: #22c55e;
}Browse interactive component docs at the hosted Storybook or run locally:
cd apps/storybook
pnpm install
pnpm storybook