dolma-ui
v0.4.3
Published
React UI components built with Base UI, CSS Modules, and Figma design tokens.
Maintainers
Readme
dolma-ui
React UI components built with Base UI, CSS Modules, and Figma design tokens.
Installation
pnpm add dolma-ui react react-domRequires React and React DOM 19.2 or later within major version 19. Import dolma-ui/style.css alongside the components.
License
Licensed under the unmodified PolyForm Noncommercial License 1.0.0. Use, modification, and redistribution are free for purposes permitted by the license. Commercial use outside those permissions requires a separate license from Artem Netsvetaev ([email protected]).
When distributing any part of the library, include the license text or its official URL.
Third-party dependencies remain subject to their own licenses.
Search
import { Search } from "dolma-ui";
import "dolma-ui/style.css";
<Search
value={query}
onValueChange={setQuery}
loading={fetching}
aria-label="Search projects"
clearLabel="Clear search"
/>;Search composes TextInput with the Figma search icon, loader, and clear button. Use defaultValue for uncontrolled input; name participates in native form submission. Clearing fires onChange and onValueChange and returns focus to the input. Loading keeps the input editable. disabled and readOnly prevent clearing. ref points to the input. Supply label, aria-label, or aria-labelledby to name the search; its default accessible name and placeholder are “Search”. clearLabel can be localized. The default width is 368px and the height uses --component-search-size-small-height (40px); override width with className or style.
TextInput also accepts endAdornment for accessible interactive content after the input, plus controlClassName and inputClassName for styling its parts.
Development
- Install dependencies:
pnpm install- Run the playground:
pnpm play- Run the unit tests:
pnpm test --run- Check JavaScript/TypeScript with Oxlint and CSS with Stylelint:
pnpm lint
pnpm lint:fix- Format with Oxfmt or check formatting without writing files:
pnpm format
pnpm format:checkIndividual lint commands are pnpm lint:js and pnpm lint:css. Generated token CSS, icon path data, Figma exports, and lockfiles are excluded from formatting; generated styles and build output are excluded from linting. Existing files have not been reformatted as part of the tooling setup.
Stylelint enforces logical CSS properties and directional keywords with stylelint-plugin-logical-css, and Baseline Newly Available support with stylelint-plugin-use-baseline (available: "newly"). The Baseline plugin uses web-features data rather than resolving the downstream browsers in .browserslistrc.
Oxlint is configured in oxlint.config.ts. It enables React Doctor's RECOMMENDED_RULES for per-file checks and eslint-plugin-baseline-js with available: "newly" for library and playground code, including stories. Baseline checks cover JavaScript syntax, detectable Web APIs, and builtins using web-features data; they do not resolve downstream browsers or TypeScript instance types. Node tooling is excluded from browser Baseline checks. React Doctor's whole-project scans require its separate CLI. Warnings also fail pnpm lint:js because it uses --deny-warnings.
The library, playground, browser tests, and Storybook use React Compiler. For those compiled TSX files, Oxlint skips React Doctor's function, object, and JSX prop identity rules, matching their disabledWhen: ["react-compiler"] metadata. Other React correctness checks remain enabled. The standalone React Doctor key-order subcheck is disabled because it reports keys already placed after spreads; missing-key checks remain enabled in both plugins.
- Build the library:
pnpm buildCheckbox and Radio
The components use Base UI and the exported light and dark Figma design tokens. Import the stylesheet once in your app:
import 'dolma-ui/style.css'
import { Checkbox, Radio, RadioGroup } from 'dolma-ui'
<Checkbox label="Enable notifications" name="notifications" />
<Checkbox label="Select all" indeterminate />
<RadioGroup aria-label="Delivery" name="delivery" defaultValue="standard">
<Radio value="standard" label="Standard" />
<Radio value="express" label="Express" />
</RadioGroup>Use checked / onCheckedChange for controlled checkboxes and value / onValueChange on RadioGroup for controlled selection. Controls without label need aria-label or an external label. Props and refs are forwarded to Base UI roots. Override CSS custom properties on an ancestor to customize the theme.
Run pnpm storybook to inspect states and interactive examples. Hover stories use real pointer hover; keyboard focus uses Tab. Browser targets are resolved from .browserslistrc: baseline newly available with downstream.
Library CSS uses native nesting and the ordered dolma-ui.tokens, dolma-ui.components, and dolma-ui.accessibility cascade layers. Unlayered application CSS overrides library defaults; Storybook styles use dolma-ui.storybook.
Icons
Icons use the original SVG exports from Figma Icons.
The variants are lg (32px), md (24px, default), sm (16px), and numeric 20 (20px). The 20px token scales the original md geometry; the original variants retain their strokes of 2.5px, 2px, and 1.5px respectively. React icons inherit currentColor. Dimensions use the Figma CSS size tokens and accept consumer overrides.
import { Icon } from 'dolma-ui'
import 'dolma-ui/style.css'
<Icon name="check" size="sm" />
<Icon name="info-circle" size="lg" aria-hidden={false} role="img" aria-label="Information" />Available names: check, close, plus, minus, chevron-down, chevron-right, chevron-left, chevron-up, info-circle.
Original SVGs are also available as dolma-ui/icons/check-sm.svg (and the corresponding name/size combinations); these retain Figma's white stroke.
After replacing SVG exports in src/icons, run node scripts/generate-icon-paths.mjs to refresh the React path data.
Component sizes
Sizes use the exported Figma tokens from figma/component_tokens.json. All component size tokens are published in dolma-ui/style.css, including tokens not yet used by a component. Override them on an ancestor or the component with CSS custom properties.
| Component | Size API / dimensions in px |
| ---------------------------------------- | -------------------------------------------------------------------------- |
| Button | xs 24, sm 32, md 40 (default), lg 48; icon-only buttons are square |
| Tag | xs 28, sm 32, md 36, lg 40 (default) |
| Avatar | xs 24, sm 32, md 40 (default), lg 56, xl 72, xxl 96 |
| Icon | sm 16, 20 20, md 24 (default), lg 32 |
| Dot | 6 or 8 (default) |
| Table.Root | sm cells start at 48, xs at 40; omit size for payment ledger spacing |
| Checkbox / Radio | 24 control; checkbox body 20, radio body 22, active dot 8 |
| Switch | 40 × 24, handle 20 |
| Chips / Counter / Badge | 32 / 16 / 24 |
| ListItem / Tabs / Search / Select / Menu | 40 |
| MenuItem | 36 |
| Alert | Minimum height 40 |
Text controls and cells can grow to fit content. Components with one Figma size do not introduce arbitrary sm/md/lg variants. Avatar sizes come from the Figma node measurements recorded in the token generator; components without component size tokens retain their documented design dimensions.
Button migration: the previous lg (40px), md (32px), sm (24px) map to md, sm, xs respectively. The default stays 40px. Token names take precedence over the Figma button variant labels, which use Large/Medium/Small for 40/32/24px.
The cell/size/x-small-width token (328px) is available for explicit column sizing via colgroup or consumer CSS; tables keep flexible column widths by default. The subnavigation and radio-dot tokens remain available as design primitives without adding unrelated public components or states.
Themes
The library follows the system color scheme by default and responds to changes automatically. Set data-theme="light" or data-theme="dark" on <html> or a container; nested containers can use a different theme. Both palettes come from figma/color_semantic_*.json, including aliases and alpha values. Primitive tokens retain their original values in both themes.
<div data-theme="light" className="surface">
<Checkbox label="Notifications" />
<Chips counter={17}>Unread</Chips>
</div>Apply background: var(--semantic-background-primary) and color: var(--semantic-text-primary) to your theme surfaces. Native browser controls follow the selected theme through color-scheme. Custom properties can be overridden with unlayered CSS on the same theme container. Storybook's theme selector uses the library palettes directly.
After updating the Figma JSON export, run pnpm tokens:generate. Run pnpm tokens:check to verify the generated stylesheet is current. Shared dimensions and typography used by components are generated with the original Figma WEB property names.
Typography uses regular Inter from Google Fonts. The token generator maps Figma's Inter Platform family to Inter. Load the font in your application's <head> (Storybook and the playground already include it):
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
/>Button
import { Button, Icon } from 'dolma-ui'
import 'dolma-ui/style.css'
<Button variant="primary" onClick={save}>Save</Button>
<Button variant="danger" size="md" leftIcon={<Icon name="close" />}>Delete</Button>
<Button variant="only" size="sm" aria-label="Add"><Icon name="plus" /></Button>
<Button loading={saving}>Save</Button>Variants match Figma: primary, secondary, tertiary, danger, and only (icon only). Sizes are lg (40px), md (32px), and sm (24px, intended for only). Loading blocks repeated activation, retains keyboard focus and the accessible label, and shows a spinner. Specify type="submit" for form submission. Base UI props and refs are forwarded; compose dialog and tooltip triggers with render={<Button />}. Use a styled anchor for navigation links. Button replaces the starter MyButton export.
Publishing
Run pnpm build-storybook to verify the component documentation, then pnpm pack --pack-destination /tmp to inspect the release archive. The package includes built JavaScript, TypeScript declarations, CSS, SVG icons, README and LICENSE.
pnpm publish runs token validation, type checking, browser tests, and the library build before publishing to npm. Authenticate with npm first. Use pnpm release for subsequent version bumps.
