# Thorbis Components

<!-- thorbis-mobile-hig-reference -->
> **Mobile platform gate (D-025):** Every mobile-app task requires the [Native contract](https://design.thorbis.com/skills/native), HIG-001–HIG-022, and relevant live [Apple Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines). Apple HIG governs iOS/iPadOS behavior over conflicting web/Linear rules. Cite rule IDs and topic URLs in specifications, component contracts, PRs, and release evidence. Android retains host conventions. Normative requirements and exceptions have one owner: Native.

The agent contract for choosing, adopting, extending, and verifying interface components in Thorbis.

Live registry: https://design.thorbis.com/components  
Markdown: https://design.thorbis.com/components.md  
Download: https://design.thorbis.com/files/COMPONENTS.md

## When to use this file

Read this file before creating or changing a Thorbis primitive, form control, menu, overlay, record, status, navigation element, or component composition. Use it to answer four questions:

1. Does the component already ship?
2. If it is only specified, what contract must the adoption satisfy?
3. Which semantic variant and surface role fit the task?
4. Which states and verification evidence are required before the component is adopted?

For page structure and product workflow, start with `DESIGN.md` and the smallest owning skill. For component implementation, this file is the component authority beneath `DESIGN.md` and `AGENTS.md`.

## Sources of truth

| Need                                                    | Canonical owner                                        |
| ------------------------------------------------------- | ------------------------------------------------------ |
| Product laws, profiles, surfaces, tokens                | `DESIGN.md`                                            |
| Agent order of operations and hard stops                | `AGENTS.md`                                            |
| Component status, name, family, import path, use, avoid | `src/data/component-catalog.ts`                        |
| Published exports and direct dependencies                | Wrapper source, checked by `scripts/component-modules.mjs` |
| Executable usage examples                                | `src/components/components/examples/*.tsx`             |
| Published setup facts and example selection              | `src/data/component-usage.ts` and `src/data/component-examples.ts` |
| Published exports and direct dependencies                | Wrapper source, checked by `scripts/component-modules.mjs` |
| Executable usage examples                                | `src/components/components/examples/*.tsx`             |
| Published setup facts and example selection              | `src/data/component-usage.ts` and `src/data/component-examples.ts` |
| Adopted React wrappers                                  | `src/components/ui/*.tsx`                              |
| Shared primitive presentation and state                 | `src/components/ui/*.stylex.ts` beside each wrapper    |
| Generated token CSS                                     | `src/styles/tokens.generated.css`                      |
| Global Thorbis tokens                                   | `src/styles.css` under `:root`; generated StyleX facade   |
| Live specimens and scroll-spy reference                 | `/components` and `src/components/components/page.tsx` |
| External accessible source behavior                     | The component's official shadcn/Radix source           |
| Operational grammar tie-breaker                         | Thorbis Ã— Linear baseline in `AGENTS.md`               |

Do not create a second token owner, a page-local component language, or a forked copy of this contract.

## Status contract

- **Adopted** means a Thorbis wrapper exists under `src/components/ui/`, composes its colocated StyleX owner and root token sheet, exposes semantic `data-slot` hooks, is represented by a live specimen, and is covered by automated checks.
- **Specified** means Thorbis has decided when to use and avoid the component, but a production wrapper does not ship yet. Its published import path is a target, not permission to import a missing file.
- A component becomes **Adopted** only in the same change that adds the wrapper, shared styling, live specimen, catalog status, state coverage, and tests.
- Never mark a component Adopted to make a check pass. Never use a Specified import path as if it exists.

## Agent workflow

1. Name the person, device, profile, pattern, surface, and primary action.
2. Search `/components`, `src/data/component-catalog.ts`, and `src/components/ui/` before writing code.
3. Reuse an Adopted wrapper exactly from its available import. Open its component page for actual exports, source, setup, and executable examples where published. Request `Accept: text/markdown` on that page or use MCP `get_document` with its path for the same information. The wrappers are repository source, not an installable npm UI package; do not infer exports from upstream names.
4. If the component is Specified, record a structural decision and adopt the official accessible source primitive. Preserve upstream semantics, focus management, keyboard behavior, portal behavior, and ARIA relationships.
5. Translate the source into Thorbis. Linear supplies the calm operational baseline; Thorbis supplies tokens, density, words, state, failure handling, and brand identity. Do not copy Linear's colors, typography, object names, or visual costume.
6. Put reusable component presentation in the colocated `*.stylex.ts` owner and consume generated tokens from `src/styles/tokens.generated.css`. A page may own arrangement around a component; it may not redefine the component's geometry, semantic prominence, focus, disabled behavior, or state language.
7. Add the live specimen and document Use and Avoid guidance.
8. Verify the component contract below, then change the catalog status to Adopted.

If the registry has no matching component or composition, stop under D-012. A miss does not authorize local invention.

## Thorbis component contract

Every adopted component must satisfy all applicable rows.

| Contract     | Required evidence                                                                                                                                                   |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Semantics    | Native element first; accessible name, role, value, and relationships remain correct.                                                                               |
| Slots        | Stable `data-slot` hooks name semantic parts; selectors do not depend on page or feature classes.                                                                   |
| Tokens       | Color, type, radius, shadow, spacing roles, and motion come from the shared token owner. No private shadows, raw hex, arbitrary gradients, feature palettes, or solid colored leading/trailing rails. |
| Geometry     | The primitive owns its control geometry. A group may normalize peer height; semantic variants still own prominence.                                                 |
| States       | Default, hover, focus-visible, active, selected/open, disabled/unavailable, loading, success, error, empty, and destructive states exist where meaningful.          |
| Async        | Keep the action word and footprint stable. Put progress or outcome on the mark, set `aria-busy`, prevent duplicate activation, and ignore or cancel stale work.     |
| Keyboard     | Logical Tab order; expected arrow/Escape/Enter/Space behavior; no unavailable activation; focus returns to the trigger after a transient layer closes.              |
| Touch        | At least 44px for touch-critical controls, expressed by an explicit touch variant/density; compact Workbench controls must not be globally promoted, and targets may not overlap. |
| Mobile       | Verify at 390px. Inputs use at least 16px text. Rebuild action priority without losing object identity or state.                                                    |
| Themes       | Dark and light are intentional retunes. Contrast, focus, status, and layer depth remain legible in both.                                                            |
| Motion       | Motion is brief and functional; `prefers-reduced-motion` removes transforms and nonessential animation.                                                             |
| Content      | Long, missing, malformed, localized, and expanded text cannot destroy geometry. Icon-only controls have accessible names.                                           |
| Failure      | Loading, empty, error, permission, offline, stale, partial, and conflict states preserve the safest useful work and a recovery path.                                |
| Verification | Typecheck, relevant component tests, production build, desktop and 390px visual check, keyboard check, both themes, reduced motion, zoom/reflow, and clean console. |

## Semantic geometry

Use meaning before appearance.

| Role                      | Thorbis treatment                                                   | Rule                                                                                         |
| ------------------------- | ------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| Commit                    | `Button` default/primary; ink surface, inverse text, compact radius | One clear commit per action neighborhood. The word stays stable during async work.           |
| Secondary action          | `Button` secondary or action-surface                                | Visible but quieter than the commit. Do not imitate primary contrast.                        |
| Reversible value/filter   | `Button` chip or a dedicated toggle                                 | Pills represent values and reversible modes, not every action.                               |
| Quiet utility             | `Button` ghost or link                                              | Use only when surrounding context carries the action. Preserve a visible path.               |
| Icon-only action          | `Button` icon                                                       | Circle, one unambiguous mark, required accessible name, tooltip when the mark is unfamiliar. |
| Destructive commit        | `Button` destructive after consequence is named                     | Do not use danger color for ordinary negative navigation.                                    |
| Grouped actions           | `ButtonGroup` with compact default and explicit density              | The group normalizes peer geometry; use `field` or `touch` only when the action neighborhood needs it. |
| Field                     | `Input`, `Textarea`, `Select`                                       | Recessed well, persistent label, help/error adjacency, visible outside focus ring.           |
| Field action neighborhood | `InputGroup`                                                        | The group owns peer geometry; Paste stays quiet and Save retains commit prominence.          |
| Contextual layer          | `Popover`                                                           | Anchored local choice; short and dismissible without losing work.                            |
| Blocking transaction      | `Dialog`                                                            | Explicit title, focus trap, Escape/close path, constrained height, focus return.             |
| Grouped record            | `Card`                                                              | Use only when grouping improves comprehension; do not make every region a card.              |

## Composition rules

- `InputGroup` accepts `compact`, `comfortable`, or `touch` density; `touch` is the default and `field` remains an alias for `comfortable`. The [constitutional control densities](https://design.thorbis.com/design.md#controls) own the visual sizes. The group applies one visual height and type size to its input and action peers, then uses touch sizing on mobile and coarse pointers. Keep a persistent label on the input itself. Density does not lower the separate hit-target requirement.
- `Input` and `NativeSelect` reserve their native target in a noninteractive `field-target` frame; IDs, refs, values, form attributes, and accessible names stay on the native control. `SelectTrigger` reserves the same field footprint around its custom selection button. `Button` reserves space for its `control-target` child, including when `asChild` supplies a link. Arrange the complete footprint, keep targets separate, and do not clip or style these internal target slots as content. Measure the visible face and the actual clickable area separately against [UI's target rule](https://design.thorbis.com/skills/ui#floor).
- Prefer `NativeSelect` for a short simple option list. `Select` owns custom single selection through its exported Radix parts. Its [published usage](https://design.thorbis.com/components/select) includes the current anatomy and migration from the earlier native wrapper; do not give it native `option` children or native change events. Searchable selection remains the separate Combobox contract.
- A route is a place. A dialog is a transaction. A popover is a local choice. A tooltip is short instruction. Do not exchange these roles to get a preferred shape.
- Prefer composition over boolean flags. Repeated flags that alter structure are a signal to split the API or use slots.
- A primitive does not know what a job, invoice, customer, technician, or inspiration item is. Product components compose primitives with trade language.
- Keep interactive descendants out of an interactive parent. Cards and rows may contain actions, but those actions must not trigger the container.
- Portalled content keeps its trigger relationship, collision behavior, viewport constraints, layering token, and focus lifecycle.
- Preserve Radix/shadcn state attributes such as `data-state`, `data-orientation`, and `data-disabled`; CSS should read them instead of duplicating state in page classes.
- `asChild` is an API for semantics, not a way to bypass disabled behavior. An unavailable slotted control must suppress navigation and child handlers before activation.
- Prefer native select, input, button, details, and table behavior when it satisfies the task. Custom behavior must earn its complexity.

## Component directory

The directory is exhaustive for the current Thorbis component registry. Open the linked detail page for the component's Avoid guidance and live/specification specimen.

| Component                                                                  | Status    | Family               | Module path (available when Adopted; proposed when Specified) | Use                                                                                                                                         |
| -------------------------------------------------------------------------- | --------- | -------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| [Accordion](https://design.thorbis.com/components/accordion)               | Adopted   | Disclosure           | `@/components/ui/accordion`        | Use when several peer explanations are optional and their headings remain useful while collapsed.                                           |
| [Alert](https://design.thorbis.com/components/alert)                       | Adopted   | Status               | `@/components/ui/alert`            | Use for durable information, caution, success, or failure that remains until the condition changes. Status lives on the title and mark, not a colored side rail. |
| [Alert Dialog](https://design.thorbis.com/components/alert-dialog)         | Adopted   | Transaction          | `@/components/ui/alert-dialog`     | Use before destructive or irreversible commits when the consequence cannot be inferred from the trigger.                                    |
| [Aspect Ratio](https://design.thorbis.com/components/aspect-ratio)         | Adopted   | Media                | `@/components/ui/aspect-ratio`     | Use for images, maps, video, and previews whose geometry must remain stable while loading.                                                  |
| [Attachment](https://design.thorbis.com/components/attachment)             | Adopted   | Record               | `@/components/ui/attachment`       | Use when a record accepts uploads or exposes durable files with clear status and recovery.                                                  |
| [Avatar](https://design.thorbis.com/components/avatar)                     | Adopted   | Identity             | `@/components/ui/avatar`           | Use beside a name when identity helps scanning or attribution.                                                                              |
| [Badge](https://design.thorbis.com/components/badge)                       | Adopted   | Status               | `@/components/ui/badge`            | Use for state, category, and small counts when the text remains readable without color.                                                     |
| [Breadcrumb](https://design.thorbis.com/components/breadcrumb)             | Adopted   | Navigation           | `@/components/ui/breadcrumb`       | Use when the parent path helps orientation and every ancestor is a real destination.                                                        |
| [Bubble](https://design.thorbis.com/components/bubble)                     | Adopted   | Conversation         | `@/components/ui/bubble`           | Use in chronological conversation where attribution and delivery state matter.                                                              |
| [Button](https://design.thorbis.com/components/button)                     | Adopted   | Action               | `@/components/ui/button`           | Use the default ink button for a commit, chip for a reversible filter, ghost for quiet utility, and icon only when the mark is unambiguous. |
| [Button Group](https://design.thorbis.com/components/button-group)         | Adopted   | Action               | `@/components/ui/button-group`     | Use for tightly related actions whose individual roles remain clear and whose hit areas never overlap.                                      |
| [Calendar](https://design.thorbis.com/components/calendar)                 | Adopted   | Date                 | `@/components/ui/calendar`         | Use when spatial date context materially improves the choice.                                                                               |
| [Card](https://design.thorbis.com/components/card)                         | Adopted   | Surface              | `@/components/ui/card`             | Use when grouping materially improves comprehension and the card has a clear internal hierarchy.                                            |
| [Carousel](https://design.thorbis.com/components/carousel)                 | Adopted   | Media                | `@/components/ui/carousel`         | Use for a bounded visual sequence when order matters and all items remain reachable.                                                        |
| [Chart](https://design.thorbis.com/components/chart)                       | Adopted   | Evidence             | `@/components/ui/chart`            | Use only when shape or comparison is faster to read visually than in a compact table.                                                       |
| [Checkbox](https://design.thorbis.com/components/checkbox)                 | Adopted   | Choice               | `@/components/ui/checkbox`         | Use when several options may be selected or a single explicit agreement is required.                                                        |
| [Collapsible](https://design.thorbis.com/components/collapsible)           | Adopted   | Disclosure           | `@/components/ui/collapsible`      | Use for secondary detail that may stay closed without blocking the task.                                                                    |
| [Combobox](https://design.thorbis.com/components/combobox)                 | Adopted   | Choice               | `@/components/ui/combobox`         | Use when scanning a native select would be slow and typed filtering improves retrieval.                                                     |
| [Command](https://design.thorbis.com/components/command)                   | Adopted   | Navigation           | `@/components/ui/command`          | Use when a large action set benefits from ranking, filtering, and a single predictable shortcut.                                            |
| [Context Menu](https://design.thorbis.com/components/context-menu)         | Adopted   | Menu                 | `@/components/ui/context-menu`     | Use as an acceleration layer when every critical action also has a visible path.                                                            |
| [Data Table](https://design.thorbis.com/components/data-table)             | Adopted   | Workbench            | `@/components/ui/data-table`       | Use for comparison and repeated operations across many structured records.                                                                  |
| [Date Picker](https://design.thorbis.com/components/date-picker)           | Adopted   | Date                 | `@/components/ui/date-picker`      | Use when constraints, ranges, or nearby dates make calendar context useful.                                                                 |
| [Dialog](https://design.thorbis.com/components/dialog)                     | Adopted   | Transaction          | `@/components/ui/dialog`           | Use for consequential confirmation or a short task that must be completed before returning.                                                 |
| [Direction](https://design.thorbis.com/components/direction)               | Adopted   | Internationalization | `@/components/ui/direction`        | Use at the language boundary so spacing, order, and directional icons adapt together.                                                       |
| [Drawer](https://design.thorbis.com/components/drawer)                     | Adopted   | Transaction          | `@/components/ui/drawer`           | Use on compact screens when a brief modal task benefits from direct-manipulation dismissal.                                                 |
| [Dropdown Menu](https://design.thorbis.com/components/dropdown-menu)       | Adopted   | Menu                 | `@/components/ui/dropdown-menu`    | Use for secondary commands that belong to one object or control.                                                                            |
| [Empty](https://design.thorbis.com/components/empty)                       | Adopted   | State                | `@/components/ui/empty`            | Use when a collection has nothing to show and distinguish first use from filtered or failed results.                                        |
| [Field](https://design.thorbis.com/components/field)                       | Adopted   | Field                | `@/components/ui/field`            | Use around every form value so accessible naming and validation remain consistent.                                                          |
| [Form](https://design.thorbis.com/components/form)                         | Adopted   | Transaction          | `@/components/ui/form`             | Use for durable data entry where submit, error recovery, and keyboard order must remain explicit.                                           |
| [Hover Card](https://design.thorbis.com/components/hover-card)             | Adopted   | Inspection           | `@/components/ui/hover-card`       | Use when a compact preview saves navigation and the same content is available on focus.                                                     |
| [Input](https://design.thorbis.com/components/input)                       | Adopted   | Field                | `@/components/ui/input`            | Use for one-line text, URL, search, number, and credential entry with a visible label.                                                      |
| [Input Group](https://design.thorbis.com/components/input-group)           | Adopted   | Field                | `@/components/ui/input-group`      | Use when adjacent content changes or acts on the same value and its reading order is unambiguous.                                           |
| [Input OTP](https://design.thorbis.com/components/input-otp)               | Adopted   | Field                | `@/components/ui/input-otp`        | Use for short verification codes when automatic fill and full-code paste are preserved.                                                     |
| [Item](https://design.thorbis.com/components/item)                         | Adopted   | Record               | `@/components/ui/item`             | Use for scannable collections where a stable row grammar improves repeated reading.                                                         |
| [Kbd](https://design.thorbis.com/components/kbd)                           | Adopted   | Instruction          | `@/components/ui/kbd`              | Use beside an available action to disclose an accelerator.                                                                                  |
| [Label](https://design.thorbis.com/components/label)                       | Adopted   | Field                | `@/components/ui/label`            | Use on every field and control group with concise task language.                                                                            |
| [Marker](https://design.thorbis.com/components/marker)                     | Adopted   | Map                  | `@/components/ui/marker`           | Use when geographic position is part of the work and an equivalent list remains available.                                                  |
| [Menubar](https://design.thorbis.com/components/menubar)                   | Adopted   | Menu                 | `@/components/ui/menubar`          | Use only when expert work genuinely benefits from persistent, conventional command groups.                                                  |
| [Message](https://design.thorbis.com/components/message)                   | Adopted   | Conversation         | `@/components/ui/message`          | Use when chronological communication is durable work rather than transient feedback.                                                        |
| [Message Scroller](https://design.thorbis.com/components/message-scroller) | Adopted   | Conversation         | `@/components/ui/message-scroller` | Use for live or long message history with explicit jump-to-latest behavior.                                                                 |
| [Native Select](https://design.thorbis.com/components/native-select)       | Adopted   | Choice               | `@/components/ui/native-select`    | Use first for a short stable option list, especially on mobile.                                                                             |
| [Navigation Menu](https://design.thorbis.com/components/navigation-menu)   | Adopted   | Navigation           | `@/components/ui/navigation-menu`  | Use for a modest hierarchy of durable routes that benefits from grouped preview.                                                            |
| [Pagination](https://design.thorbis.com/components/pagination)             | Adopted   | Navigation           | `@/components/ui/pagination`       | Use when result position and shareable page boundaries matter.                                                                              |
| [Popover](https://design.thorbis.com/components/popover)                   | Adopted   | Choice               | `@/components/ui/popover`          | Use when the task is brief, contextual, and can close without losing work.                                                                  |
| [Progress](https://design.thorbis.com/components/progress)                 | Adopted   | Status               | `@/components/ui/progress`         | Use when the system knows total work and progress materially helps expectation.                                                             |
| [Questionnaire](https://design.thorbis.com/components/questionnaire)       | Adopted   | Guided               | `@/components/ui/questionnaire`    | Use for guided intake where ordering and conditional follow-up reduce cognitive load.                                                       |
| [Radio Group](https://design.thorbis.com/components/radio-group)           | Adopted   | Choice               | `@/components/ui/radio-group`      | Use when all options should be compared before choosing one.                                                                                |
| [Resizable](https://design.thorbis.com/components/resizable)               | Adopted   | Workbench            | `@/components/ui/resizable`        | Use in expert workbenches when people need to balance adjacent durable regions.                                                             |
| [Scroll Area](https://design.thorbis.com/components/scroll-area)           | Adopted   | Viewport             | `@/components/ui/scroll-area`      | Use only when a contained region must scroll independently from the route.                                                                  |
| [Select](https://design.thorbis.com/components/select)                     | Adopted   | Choice               | `@/components/ui/select`           | Use when the list is concise, the current value matters, and native select is insufficient.                                                 |
| [Separator](https://design.thorbis.com/components/separator)               | Adopted   | Structure            | `@/components/ui/separator`        | Use between adjacent regions when spacing alone does not explain the relationship.                                                          |
| [Sheet](https://design.thorbis.com/components/sheet)                       | Adopted   | Transaction          | `@/components/ui/sheet`            | Use when context should remain visible behind a compact transaction.                                                                        |
| [Sidebar](https://design.thorbis.com/components/sidebar)                   | Adopted   | Shell                | `@/components/ui/sidebar`          | Use only at the shell owner so pages cannot change its geometry or navigation contract.                                                     |
| [Skeleton](https://design.thorbis.com/components/skeleton)                 | Adopted   | State                | `@/components/ui/skeleton`         | Use when a response delay is perceptible and the final geometry is known.                                                                   |
| [Slider](https://design.thorbis.com/components/slider)                     | Adopted   | Choice               | `@/components/ui/slider`           | Use when relative position matters more than exact entry and expose the current value.                                                      |
| [Spinner](https://design.thorbis.com/components/spinner)                   | Adopted   | State                | `@/components/ui/spinner`          | Use when work is underway but progress cannot be measured; keep the action word when present.                                               |
| [Switch](https://design.thorbis.com/components/switch)                     | Adopted   | Choice               | `@/components/ui/switch`           | Use for reversible settings where the current state is more important than submitting a form.                                               |
| [Table](https://design.thorbis.com/components/table)                       | Adopted   | Evidence             | `@/components/ui/table`            | Use when values share attributes and people need to compare them precisely.                                                                 |
| [Tabs](https://design.thorbis.com/components/tabs)                         | Adopted   | Navigation           | `@/components/ui/tabs`             | Use for a small bounded set of parallel views that do not need separate navigation history.                                                 |
| [Textarea](https://design.thorbis.com/components/textarea)                 | Adopted   | Field                | `@/components/ui/textarea`         | Use when the expected answer needs sentences or line breaks, with a visible label and limits.                                               |
| [Toast](https://design.thorbis.com/components/toast)                       | Adopted   | Status               | `@/components/ui/toast`            | Use after a reversible background action when inline state already records the durable result.                                              |
| [Toggle](https://design.thorbis.com/components/toggle)                     | Adopted   | Choice               | `@/components/ui/toggle`           | Use when the selected state is visible, immediate, and can be named accessibly.                                                             |
| [Toggle Group](https://design.thorbis.com/components/toggle-group)         | Adopted   | Choice               | `@/components/ui/toggle-group`     | Use for bounded view modes or filters with short, mutually understandable labels.                                                           |
| [Tooltip](https://design.thorbis.com/components/tooltip)                   | Adopted   | Instruction          | `@/components/ui/tooltip`          | Use to name an icon-only control or clarify unfamiliar compact notation.                                                                    |
| [Typography](https://design.thorbis.com/components/typography)             | Adopted   | Content              | `@/components/ui/typography`       | Use semantic elements first, then the published type roles and 65â€“75ch reading measure.                                                     |

## Adoption checklist

- [ ] Structural decision records person, device, profile, pattern, and surface.
- [ ] Catalog and tree were searched; no Adopted component already solves the problem.
- [ ] Official accessible source behavior is preserved.
- [ ] Wrapper composes its colocated StyleX owner and exposes semantic `data-slot` hooks.
- [ ] Tokens and semantic variants own presentation; no page class leaks into the primitive.
- [ ] Applicable state, failure, keyboard, touch, theme, and reduced-motion contracts are implemented.
- [ ] Live specimen demonstrates real Thorbis words and stable geometry.
- [ ] Catalog entry includes Use and Avoid guidance and changes to Adopted only when implementation ships.
- [ ] Automated coverage discovers the wrapper and matches it to the catalog.
- [ ] Typecheck, tests, build, desktop, 390px, keyboard, both themes, zoom/reflow, reduced motion, and console are verified.

Two failed boxes means the component is not adopted.

## Applied bookmark research

Reviewed 2026-09-06. These are Thorbis applications and review exercises, not replacements for DESIGN.md, COMPONENTS.md, or the owning skill. Linear remains the operational baseline. External advice that conflicts with the constitution stays out.

These worked examples are not a claim that the product behaviors have been implemented or verified.

### Make invalid combinations difficult to express

Owning skill: [composition](https://design.thorbis.com/skills/composition).

Independent loading, success, and error flags can contradict each other; presentation and business logic become tangled as a component grows.

Choose an explicit state model and a semantic composition API. Reuse the approved primitives, keep domain operations outside them, and locate loading boundaries according to the work they protect. Documentation names which variants actually ship.

**Thorbis example:** A payment dialog composes an approved trigger, content, fields, and actions around a domain-owned operation. The button receives one coherent request state, not several competing booleans and a private set of colors.

**Verify:** Exercise each valid state and transition, keyboard and focus behavior, controlled and uncontrolled contracts where supported, server-rendered output, and slow or missing data. Check provenance and license before source adoption.

**Do not import:** No arbitrary color escape hatch, duplicate component kit, unregistered dependency, or migration from Astro merely because a source uses RSC.

Evidence: [React handbook](https://devouringdetails.com/resources/react-handbook); [components.build](https://www.components.build/); [Component Architecture for React Server Components](https://aurorascharff.no/posts/component-architecture-for-react-server-components); [shadcncraft](https://shadcncraft.com/). [Source access limits](https://design.thorbis.com/research/bookmarks#application-composition).

### A control keeps its meaning through every state

Owning skill: [ui](https://design.thorbis.com/skills/ui).

A button that changes width, a field that loses input, or a dialog that loses focus breaks the task even when the resting design looks precise.

Review the approved primitive as a sequence: resting, focused, activated, pending, resolved, and recovered. Keep the action label and footprint stable, associate errors with their fields, and preserve a visible keyboard path.

**Thorbis example:** Save estimate remains Save estimate while its state mark changes. A validation error keeps the entered values, explains the repair beside the field, and moves focus only when the interaction calls for it.

**Verify:** Test Tab, Shift-Tab, Enter, Escape where applicable, paste, invalid input, rapid activation, and a slow response. Repeat at 390px, in both themes, with zoom and reduced motion.

**Do not import:** No hand-built duplicate primitive, hidden label, disabled browser zoom, or borrowed shadow-only outer edge that violates D-017.

Evidence: [Web Interface Guidelines](https://vercel.com/design/guidelines); [Invisible Details](https://invisibledetails.com/); [components.build](https://www.components.build/); [Details that make interfaces feel better](https://interfaces.dev/magazine/issues/details-that-make-interfaces-feel-better). [Source access limits](https://design.thorbis.com/research/bookmarks#application-ui).

[All 26 sources and review limits](https://design.thorbis.com/research/bookmarks).

