@serenis/ui
Main UI component library for the Serenis design system. Provides reusable React components with Storybook documentation, design-token integration, and accessibility support. Components are styled with colocated CSS Modules and @serenis/design-tokens.
Install
npm install @serenis/ui
Quick start
# Build
yarn workspace @serenis/ui build
# Dev (watch mode)
yarn workspace @serenis/ui dev
# Test
yarn workspace @serenis/ui test
# Typecheck
yarn workspace @serenis/ui typecheck
# Lint
yarn workspace @serenis/ui lint
yarn workspace @serenis/ui lint:css
When consuming the published package from npm, load component CSS modules once with import '@serenis/ui/css'. This ships a single dist/index.css for all CSS-module components. Monorepo apps that resolve @serenis/ui to source must not import it (the app bundler handles *.module.css). Per-component CSS loading may replace this later.
import '@serenis/ui/css'
import { cx } from '@serenis/design-tokens'
import { Button, Card } from '@serenis/ui'
;<Card>
<div className={cx('flex', 'flex-col', 'gap-sm')}>
<h2 className={cx('typography-h2')}>Session details</h2>
<p className={cx('typography-paragraph', 'text-neutral-80')}>Your next session is scheduled for tomorrow.</p>
<Button kind="primary">Confirm</Button>
</div>
</Card>
Directory structure
libraries/ui/
├── src/
│ ├── {ComponentName}/
│ │ ├── index.tsx # Main component (or {ComponentName}.tsx)
│ │ ├── index.test.tsx # Tests
│ │ ├── Playground.stories.tsx # Primary Storybook story
│ │ ├── Overview.mdx # Component documentation
│ │ └── types.ts # Type definitions (if complex)
│ ├── Form/ # Composite form module
│ │ ├── TextField/
│ │ ├── TextAreaField/
│ │ ├── SelectField/
│ │ ├── PasswordField/
│ │ ├── PhoneNumberField/
│ │ ├── PinCodeField/
│ │ ├── Autocomplete/
│ │ ├── MultiSelect/
│ │ ├── Checkbox/
│ │ ├── CheckboxButton/
│ │ ├── Radio/
│ │ ├── RadioButton/
│ │ ├── SliderField/
│ │ ├── Switch/
│ │ ├── SwitchField/
│ │ ├── FileUploadField/
│ │ ├── internal/ # Shared internal chrome and styles
│ ├── utils/ # Shared utilities (shouldForwardProp)
│ └── index.ts # Public API barrel
├── dist/ # Built output (gitignored)
├── tsup.config.ts # Bundle config
└── package.json
Component catalog
Categories match Storybook (*.stories.tsx / Overview.mdx <Meta title>): General, Data Display, Feedback, Form, Navigation, Layout.
General
| Component | Description |
| Button | Primary interactive element — actions, submits, navigation |
| Text | Deprecated. Typographic primitive |
Data Display
| Component | Description |
| Accordion | Expandable section with trigger and collapsible content |
| AccordionList | Convenience wrapper that renders multiple Accordions |
| Avatar | Circular image with name-based acronym fallback |
| Badge | Corner indicator for counts and presence (numeric or custom content) |
| Card | Foundational surface with elevation, outline, and background variants |
| Chip | Compact status label with icon and kind-based coloring |
| Quote | Semantic blockquote with left border accent |
| Suggestion | Contextual note with role="note" and kind-specific background |
| Tabs | Tabbed interface with WAI-ARIA tabs pattern and overflow |
| SegmentedControl | Segment-style tab switcher for 2–5 options |
| Tile | Card with icon, title, description, and action slot |
| Modal | Centered dialog with drag-to-dismiss, focus trap, compound API |
| Drawer | Slide-in panel (bottom on mobile, right on desktop), compound API |
| BottomSheet | Mobile bottom sheet with multi-step heights, drag-to-resize |
| Popover | Click-triggered floating content anchored to a reference element |
| Tooltip | Hover/focus-triggered floating info anchored to a reference element |
Feedback
| Component | Description |
| Alert | Status banner with role="alert", icon, and action slot |
| Loader | SVG spinner with prefers-reduced-motion support |
| Skeleton | Loading placeholder with shimmer animation and typography alignment |
The barrel also exports lower-level primitives (TextInput, TextArea, Select, Checkbox, Radio, Switch, Hint, Label) for advanced use — prefer the field components below in product code.
| Component | Description |
| TextField | Text input with floating label, hint/error, ARIA wiring |
| TextAreaField | Multi-line variant of TextField |
| SelectField | Native select with floating label and hint/error |
| PasswordField | TextField with visibility toggle |
| PhoneNumberField | TextField with phone-specific input defaults (type, inputMode, autoComplete) |
| PinCodeField | Segmented OTP input |
| Autocomplete | TextField with floating suggestions dropdown |
| MultiSelect | Multi-select combobox with chips and checkbox listbox |
| CheckboxButton | Card-style checkbox with label and hint |
| RadioButton | Card-style radio with label and hint |
| SliderField | Single choice on an ordered scale, drawn as a track with a thumb |
| SwitchField | Inline switch with label, hint, and labelPosition |
| FileUploadField | Drag-and-drop file upload with react-dropzone |
Navigation
| Component | Description |
| Link | Styled anchor for inline text links |
| NavigationButton | List-item button for menus and action lists |
| BottomBar | Fixed-position mobile bottom navigation bar |
| Breadcrumbs | Navigation breadcrumb trail with chevron separators |
| NavBar | Main navigation with a sliding active indicator |
| NavBarGroup | Capsule of NavBarItems inside NavBar |
| NavBarItem | Icon-and-label item for NavBarGroup, polymorphic via as |
| SideBar | Collapsible sidebar navigation |
| SideBarItem | Navigation item for SideBar (wraps NavigationButton) |
| SideBarUser | User avatar + name/email display for SideBar bottom slot |
| TopBar | Sticky header with logo and back navigation |
| TopBarBack | Back link with chevron icon for TopBar's back slot |
Layout
| Component | Description |
| Divider | Horizontal/vertical separator line |
Dependencies
| Dependency | Role |
@serenis/cdk | Interactive primitives (Pressable, Expandable) |
@serenis/design-tokens | Colors, spacing, typography, elevation, border radius |
@serenis/icons | Icon components for Button, Alert, Accordion, etc. |
@serenis/hooks | Shared React hooks |
@serenis/numbers, @serenis/strings | Formatting utilities |
styled-components | CSS-in-JS (uses @sanity/styled-components fork) |
@floating-ui/react | Positioning for Popover, Tooltip, Modal, Drawer, BottomSheet, Autocomplete |
framer-motion | Animations for Modal, BottomSheet |
react-dropzone | File upload for FileUploadField |
Styling conventions
- CSS Modules: each component owns its styles in a colocated
index.module.css; no utility classes in component source. See docs/agents/styling.md.
- Design tokens for all visual values — never hardcode hex colors, pixel sizes, or font values.
Documentation
- Storybook: Every component has a
Playground.stories.tsx and an Overview.mdx next to its source in libraries/ui/src/{ComponentName}/
- Overview.mdx: Comprehensive documentation with props, patterns, dos/don'ts, and known exceptions
- AGENTS.md: Agent-oriented API reference — see AGENTS.md
Consumers
- Apps:
apps/web (primary), apps/blog, apps/nutrition-blog, apps/website, apps/design-system (Storybook host)
- Libraries:
libraries/shared-components (@serenis/shared-components), libraries/ui-deprecated (legacy — prefer @serenis/ui)
Build
Bundled with tsup into ESM + CJS + TypeScript declarations. Workspace dependencies are externalized.
License
PolyForm Noncommercial 1.0.0 — see LICENSE for the full text.