콘텐츠로 이동

Component contract

이 콘텐츠는 아직 번역되지 않았습니다.

Every platform exposes the same component names, variants, sizes, and tones.

Component Options Rule
Button variant: primary, secondary, ghost, danger. size: sm, md, lg. disabled, loading Use at most one primary button per view, with a verb for the label. Secondary buttons are outlined. Renders as a rounded rectangle for pointer input and a capsule for touch
TextField label, description, error, disabled Always display a visible label; placeholder text is not a substitute for a label
Text variant: the type roles. tone: primary, secondary, accent, danger, success, warning Choose the semantic element for the document outline and set its visual style with variant
Badge tone: neutral, accent, success, warning, danger. dot Pill-shaped. The text label carries the meaning, while color reinforces it
Banner tone: info, success, warning, danger. title Each tone uses a distinct mark shape; warnings and errors announce immediately to screen readers
Card title, description, actions, flush Separated from the page by a hairline border and subtle shadow. flush removes internal padding when the card wraps a list
Divider, Spinner A spinner is announced to assistive technologies only when given a label
Switch checked, label, disabled Used for settings that take effect immediately. Remains clearly visible when off, with a track that holds 3:1 contrast against the page
Checkbox checked, label, disabled Used for selections that are applied later when submitting a form
SegmentedControl options, value, full width The active segment is raised: a hairline border, a faint shadow, and a darker label set it apart from the track
Avatar name. size: sm, md, lg Displays initials visually while exposing the full name to assistive technologies
ProgressBar value from 0 to 1, label Used for operations with known progress; use a Spinner for indeterminate work
Icon name, size: sm, md, lg, label Inherits the surrounding text color. Treated as decorative unless given a label. Arrows and chevrons can mirror in right-to-left layouts
ListRow title, description, leading, trailing, chevron, disabled Interactive when given an action. Separate adjacent rows with a Divider

Three additional navigation components exist only on the touch-oriented platforms (React Native and Compose):

Component Options Rule
TopBar title, back action, trailing Matches the page background with no bottom border. The back button is a circular control whose press area is as large as the minimum touch target
TabBar items (label and icon), value Holds three to five top-level destinations. Floats above the bottom edge as a capsule, with the active tab enclosed in its own pill so selection does not depend on color
BottomSheet open, title, content Floats inset from the screen edges. Closes when tapping the scrim, dragging down, or pressing the back button

Icons are passed as slots: a TabBar item or a ListRow accepts any element, and Icon is the component the design system provides.

Interactive states:

State Rule
hover, pressed Each state steps one shade darker; touch devices do not use hover. Pressing a button also scales it down slightly, providing non-color feedback
focus Focus rings appear only during keyboard navigation
disabled Recolored using dedicated disabled tokens rather than reduced opacity, since a semi-transparent colored fill can still look interactive
loading Preserves both its text label (keeping button width stable) and its active colors, since the action is in progress rather than unavailable
invalid Switches to a thicker red border and replaces the helper description with the error message; clear the error state as soon as the user edits the field

Clearing the error state on edit avoids a common web form trap: when an invalid state blocks form submission, leaving the field marked invalid while the user types prevents them from submitting the corrected value.

Web Desktop Mobile Kotlin
Package @acme/ui acme-ui @acme/ui-native kotlin/ui
Built on HeroUI v3 (React Aria) and native inputs GPUI Component React Native primitives Compose foundation
Runs on Browsers macOS iOS, Android Android, iOS, desktop (JVM)
Tokens arrive as CSS custom properties and a Tailwind theme Rust constants TypeScript constants Compose values (Color, Dp, TextStyle)
Sizes Follow the input device Pointer Touch Touch on phones, pointer on desktop
Design preview /design acme --design /design The button on the home screen

On the web, heroui-theme.css maps HeroUI’s theme variables to the generated tokens, and components.css applies the token sizes and state colors to HeroUI’s button and input primitives. Those two stylesheets are the only files coupled to HeroUI’s internal naming. Button and TextField wrap HeroUI components for their interaction and accessibility behavior. Switch, Checkbox, and SegmentedControl use native HTML inputs (a checkbox or radio group) with custom visuals drawn alongside a hidden input, so keyboard navigation, forms, and screen readers interact with standard controls. The remaining components are plain HTML elements styled with Tailwind utilities. Any unwrapped HeroUI component still inherits the token colors and border radii through the theme variables.

On desktop, acme_ui::set_mode applies the generated tokens to GPUI Component’s theme. button, switch, and checkbox return GPUI Component controls configured with token values, while Badge, Banner, TextField, SegmentedControl, Avatar, ProgressBar, ListRow, card, divider, and text are rendered directly with GPUI primitives.

On mobile, components are built directly on React Native’s Pressable and TextInput without a third-party UI library, and text scales with the OS font size preference.

The Kotlin client is a single Compose Multiplatform library targeting Android, iOS, and desktop. Like the React Native implementation, it builds on Compose foundation without Material components so that all styling comes directly from the tokens.

Platform differences:

Difference
Disabled controls Web, mobile, and Compose recolor disabled controls with dedicated tokens; on the GPUI desktop client, GPUI Component dims buttons, switches, and checkboxes with opacity
An invalid field Web and mobile thicken the field border; desktop draws a second outline around the field
The banner’s mark Web renders a shape icon; desktop and mobile render a letter inside a circle

Every platform includes a design preview screen that renders all tokens and components in the same order: colors, typography, spacing/radius/sizes, buttons, text fields, selection controls, badges, banners, cards, lists, and (on touch platforms) navigation components. This makes it easy to place two platforms side by side for visual comparison. Color swatches are generated directly from the token exports, so newly added color tokens appear in the preview automatically.

How to open it Entry point Light and dark
Web mise run //web:dev, then http://localhost:5173/design The button on the home screen Follows the system. ?theme=light and ?theme=dark pin the mode
Desktop mise run //desktop:design or acme --design The button in the home window Follows the system. Use the window toggle button, or pass --light or --dark
Mobile The /design screen The button on the home screen Follows the system
Kotlin mise run //kotlin:design on desktop; the home screen button elsewhere The button on the home screen Follows the system. Includes an in-app mode switch

To support automated screenshot scripts that cannot scroll or tap interactively: web sections expose URL hash anchors (/design#buttons), the desktop binary accepts --scroll <pixels>, and the mobile preview accepts ?from=<section number> and ?sheet=1.

On the web, the preview code is lazy-loaded only when navigating to /design. Static file hosts must be configured to serve index.html for /design.