zinc:ui/kit v2: plan (from GPUI, Zed ui, GPUI Kit, guise)
Research summary, 2026-09-28. Sources:
Ideas worth borrowing
- Overlays, from GPUI.
deferred(child)paints after all ancestors, with a zpriority, while keeping its layout in the tree.anchored()positions by a corner. It flips (SwitchAnchor) or snaps to the window with a margin.occlude()blocks hits to what lies below.- Popover menus combine all three.
- Keyboard, from GPUI. Actions declared on elements, with
key_contextscopes. A keymap binds keys to actions per context, and the deepest context on the focus path wins.keysFor(action)gives the shortcut hints shown in tooltips and menus. - Focus, from GPUI. Explicit tab stops and a
tab_index,focus_visiblestyles, and focus restored when a menu is dismissed. - Zed
ui.- One button base with styles Filled / Tinted / Outlined / Subtle / Transparent and sizes from 16 to 32 px.
- Per-corner rounding, for button groups.
- Five elevation levels, each fixing a surface colour and a shadow.
- A state matrix in the theme: element and ghost colours for hover, active, selected and disabled.
Tooltip::for_action, which shows the keybinding.
- GPUI Kit.
- A split between
base, the unstyled behaviour (focus, keyboard, controlled state, overlays), and the styled components. - A Root that mounts the dialog, sheet and notification layers, so apps call
openDialog/pushNotification. - A focus trap in dialogs and sheets.
- A DataTable driven by a delegate (row and column counts,
renderCell, sort, load more) with virtual rows. - A Command palette with groups and keybinding hints.
- A split between
- guise.
- One prop vocabulary for every control:
variant,color,size(xs–xl),radius,disabled. surface(color, variant)derives the fill, hover and outline colours.- About 130 components grouped as actions, forms, feedback, data, overlays, navigation and layout.
- One prop vocabulary for every control:
Engine additions (lib/std/ui.ts), in this order
- Layers.
ui.openLayer(node, { priority, modal, backdrop }). A layer paints after the root and is hit-tested first. It escapesoverflowclipping. A modal layer occludes everything below it. - Anchored positioning.
ui.anchor(float, target | [x, y], placement, offset, flip, margin), applied at the end of layout so the float never lags a frame. - Dismissal.
ui.onOutsidePointer(h, f), and a dismiss stack that Escape pops (the topmost overlay closes first). - Focus.
tabIndex,disabled,ui.focusScope(h, { trap, restore, autoFocus }).focus-visible:andring-*tokens, replacing the fixed yellow focus ring.
- Classes.
- Per-corner
rounded-{t,b,l,r,tl,…}-*andmin/max-w/h-*. truncate/line-clampanddisabled:.transitionon opacity and transform, androtate.
- Per-corner
- Keymap.
ui.bindKeys, akeyContextattribute,ui.onAction,ui.keysFor. - Icons and text. An
<Icon name>host tag: a Lucide subset (ISC licence) flattened to strokes and baked per program, like fonts. Plusui.measureText. - Lists and timers.
- Variable-height
virtualizeandscrollToIndex(i, 'nearest' | 'center'); a 2-D virtual table. - A cancellable
ui.timer, for tooltip delays and toast auto-hide. - Animating to a measured height, for accordions.
- Variable-height
Glue for both UI models.
<Portal layer>: open the layer on mount, close it on cleanup.usePresence(open): keep the node mounted through its exit animation.createDisclosure({ open, defaultOpen, onOpenChange }).
Components, in phases
- Foundations.
- Theme v2: the state matrix, status colours info / success / warning / danger, and size, radius and elevation scales.
- Shared props on every control:
variant,size,disabled,class,tooltip. - Components:
- Actions: Icon, Button v2 (icon, loading, link and tinted variants), IconButton, ButtonGroup, Toggle / ToggleGroup / SegmentedControl.
- Form controls: Checkbox, RadioGroup, Switch v2, Slider v2, Label / Field, TextInput (prefix, suffix, clear, reveal), Textarea.
- Feedback and misc: Spinner, Skeleton, Kbd v2.
- Overlays: Tooltip, Popover, Menu / DropdownMenu (checkable items, submenus, shortcuts), ContextMenu, Select, Dialog / AlertDialog, Sheet, Toast (imperative
toast({...})and one<Toaster />), HoverCard. - Navigation and data: Collapsible, Accordion, Tabs v2, Breadcrumb, Pagination, Sidebar, Command palette, Combobox, Tree, VirtualList v2, Table, DataTable (delegate props).
- Advanced: Resizable / Splitter, NumberInput, OtpInput, Calendar / DatePicker, ColorPicker, Stepper, Timeline, AvatarGroup, RingProgress, Carousel. Chart and Dock only when someone needs them.
Layout, tests, docs
- Code. Put behaviour in
lib/std/kit/base/(disclosure, roving focus, listbox, typeahead, presence) and styling inlib/std/kit/*.tsx. - Tests. One conformance test per component, in
tests/conformance/kit_*_{solid,react}.tsx. Each prints its layout and replays input with the test hooks; the Solid and React outputs must match. - Docs.
docs/ui-kit.mdis the index. Each family gets its own page,docs/ui-kit/{actions,forms,overlays,navigation,data,feedback,layout}.md.- Every component documents: an example, a props table, a keyboard table, notes for Solid / React, and limits.
- Examples.
- Rebuild
examples/ui/kit-gallery: a sidebar of the families, ⌘K to jump to a component, a theme and accent switcher, a props playground. - Add
examples/ui/kit-app: a realistic settings and data-table screen.
- Rebuild
Already covered by this pass, outside the kit: rounded overflow clipping, macOS-like scrolling, per-side borders, CSS-like text colour inheritance, and a draggable Slider.