Deviations from Untitled UI

This library takes Untitled UI as its reference, but it is a React Native library, not a port. In 16 places across 21 decisions, our API deliberately differs — to fit two orthogonal axes where Untitled UI flattened them, to follow the React Aria substrate instead of a UUI-ism layered over it, to honor a 44pt touch-target floor, or to keep one name for one idea library-wide. Each row below is a kept choice with its reasoning, not a gap to close. The same reasoning appears on each component's own page; this is the whole ledger in one read.

Avatar

1 kept choice
Untitled UI
`initials?: string` precomputed
Ours
`name?: string`, initials derived
Callers have names, not initials; deriving centralizes locale-aware initial logic. `status` adds `'busy'`; `source` is RN `ImageSourcePropType`.

Badge

1 kept choice
Untitled UI
`type` conflates shape and fill (`pill-color` / `badge-color` / `badge-modern`); a single `color` axis with 12 values
Ours
`variant` (`subtle | solid | outline | modern`) × `tone` × `shape` (`pill | square`)
Fill (variant), semantic/accent color (tone), and outline shape (shape) are three orthogonal axes instead of Untitled UI’s conflated `type`. Resolving the earlier Phase 4 decision, the seven non-semantic accent tones (`gray-blue`, `blue-light`, `blue`, `indigo`, `purple`, `pink`, `orange`) were added via accent ramps in `@ivim/isomorphic/branding`, and the `shape` axis expresses the pill-vs-badge distinction.

BottomSheet

1 kept choice
Untitled UI
`slideout-menus` (side drawer)
Ours
`BottomSheet`
Bottom sheets are the native-mobile equivalent of desktop slideouts; a side drawer is a web pattern.

Button

3 kept choices
Untitled UI
`color` single axis, 9 values (`"secondary-destructive"`, …)
Ours
`variant` (4) × `tone` (3)
The 9-value union is a partial flattening of a 4×3 grid. Two orthogonal axes are more regular, express combinations UUI omits, and keep `destructive` a tone rather than a suffix. Mapping: `primary` → `variant="primary" tone="brand"`; `secondary` → `variant="secondary" tone="gray"`; `tertiary` → `variant="tertiary" tone="gray"`; `link-color` → `variant="link" tone="brand"`; `link-gray` → `variant="link" tone="gray"`; any `*-destructive` → the same `variant` with `tone="destructive"`.
Untitled UI
Icon-only via the same Button
Ours
a separate `IconButton` with a required `label`
Icon-only buttons need an accessible name; a required prop on a dedicated component makes that unforgettable.
Untitled UI
default `size="sm"`
Ours
default `size="md"`
UUI defaults to desktop density; mobile requires a 44pt touch-target floor. Grammar rule G12.

Checkbox

1 kept choice
Untitled UI
`hint?: ReactNode` doubling as error text when invalid
Ours
`description` + `errorMessage`
UUI's `hint` is a UUI-ism layered over React Aria, which itself uses `description`/`errorMessage`. We follow the substrate; both slots can render simultaneously.

chip

1 kept choice
Untitled UI
No Chip; `Badge` (status/count) and `Tag`/`TagGroup` (removable/selectable pills) cover the space
Ours
`Chip`, now deprecated toward `Badge` (with `onPress`) and `TagGroup`
Chip was a library-specific pill that overlapped Badge and TagGroup. Resolving the Phase 4 decision, it is deprecated (kept functional, marked `@deprecated`) rather than removed, and its callers migrate to Badge / TagGroup.

Menu

2 kept choices
Untitled UI
Compound children (`Select.Item`, `Dropdown.Root/Popover/Menu`, `Tabs.List/Panel`)
Ours
data-driven `items` / `options` / `columns` arrays
RN has no DOM portals and compound context patterns complicate static typing and testing. Typed arrays are serializable, exhaustively checkable, and match RN list idioms. See grammar rule G8.
Untitled UI
`selectionIndicator` includes `"toggle"`; default `"checkmark"`
Ours
`selectionIndicator: "checkmark" | "checkbox" | "radio" | "none"`; default `"none"`
The `"toggle"` indicator has no RN precedent in this library, so it is omitted. The default is `"none"` rather than UUI's `"checkmark"` because selection previously rendered only as a row highlight — defaulting to a glyph would silently add a checkmark to every selected item across existing menus.

Input

1 kept choice
Untitled UI
`hint?: ReactNode` doubling as error text when invalid
Ours
`description` + `errorMessage`
UUI's `hint` is a UUI-ism layered over React Aria, which itself uses `description`/`errorMessage`. We follow the substrate; both slots can render simultaneously.

Progress

1 kept choice
Untitled UI
`labelPosition` / `labelFormatter` / `valueFormatter`
Ours
`labelPlacement` / `formatValue`
Kept: an internally consistent pair shared by Slider, Progress, and ProgressCircle. A cross-library rename would churn three APIs for cosmetic parity.

Radio

1 kept choice
Untitled UI
`hint?: ReactNode` doubling as error text when invalid
Ours
`description` + `errorMessage`
UUI's `hint` is a UUI-ism layered over React Aria, which itself uses `description`/`errorMessage`. We follow the substrate; both slots can render simultaneously.

Select

2 kept choices
Untitled UI
`hint?: ReactNode` doubling as error text when invalid
Ours
`description` + `errorMessage`
UUI's `hint` is a UUI-ism layered over React Aria, which itself uses `description`/`errorMessage`. We follow the substrate; both slots can render simultaneously.
Untitled UI
Compound children (`Select.Item`, `Dropdown.Root/Popover/Menu`, `Tabs.List/Panel`)
Ours
data-driven `items` / `options` / `columns` arrays
RN has no DOM portals and compound context patterns complicate static typing and testing. Typed arrays are serializable, exhaustively checkable, and match RN list idioms. See grammar rule G8.

Slider

1 kept choice
Untitled UI
`labelPosition` / `labelFormatter` / `valueFormatter`
Ours
`labelPlacement` / `formatValue`
Kept: an internally consistent pair shared by Slider, Progress, and ProgressCircle. A cross-library rename would churn three APIs for cosmetic parity.

TagGroup

2 kept choices
Untitled UI
Compound children (`Select.Item`, `Dropdown.Root/Popover/Menu`, `Tabs.List/Panel`)
Ours
data-driven `items` / `options` / `columns` arrays
RN has no DOM portals and compound context patterns complicate static typing and testing. Typed arrays are serializable, exhaustively checkable, and match RN list idioms. See grammar rule G8.
Untitled UI
item `id`
Ours
item `value`
`value` is the library-wide key prop on all option/item types (G8); one name everywhere.

TextArea

1 kept choice
Untitled UI
`hint?: ReactNode` doubling as error text when invalid
Ours
`description` + `errorMessage`
UUI's `hint` is a UUI-ism layered over React Aria, which itself uses `description`/`errorMessage`. We follow the substrate; both slots can render simultaneously.

Toggle

1 kept choice
Untitled UI
`hint?: ReactNode` doubling as error text when invalid
Ours
`description` + `errorMessage`
UUI's `hint` is a UUI-ism layered over React Aria, which itself uses `description`/`errorMessage`. We follow the substrate; both slots can render simultaneously.

Tooltip

1 kept choice
Untitled UI
12 placements incl. `left` / `right`
Ours
6 top/bottom placements
Horizontal placements are rarely usable on narrow screens; the overlay positioner supports top/bottom flipping only.