Skip to main content
Mantı UI logoMantı UIv0.12.1
Studio

v0.9.0

Released 2026-08-08.

Size travels with the surface a control opens

A sm Select used to open a listbox with md rows. The popup is portalled out of the control, so data-size on the root never reached it, and every popup rendered at one fixed size no matter what the trigger was set to. The same held for Combobox, and Menu, Listbox, DatePicker, TimePicker, and ColorPicker had no size at all.

sm | md | lg is now one shared rhythm, resolved from a --manti-size-* channel in packages/styles/src/size.css: type, supporting type, icon, control height and padding, panel padding and gap, item padding, gap and radius, and the square cell used by calendar and time grids.

<Select size="sm" items={items} />
<Menu size="lg" trigger={<Button>Actions</Button>} items={items} />

Each adapter re-stamps data-size on its positioner, so the portalled surface resolves the same step as the control that opened it. Menu and ContextMenu gain a size prop that submenus inherit; Listbox, DatePicker, TimePicker, and ColorPicker gain one too. ColorPicker's panel is a saturation canvas with no rows to rescale, so size there covers the trigger.

Every value on those surfaces derives from the spacing, type, radius, and control-height scales, so retuning --manti-space-1 or --manti-text-base rescales popups too, and a theme can retune a single step by redeclaring one channel variable under [data-size='sm']. Each sizing value is also a public component token defaulting to the channel (--manti-select-item-padding-y, --manti-menu-item-font-size, --manti-date-picker-cell-size, and so on), so a single component can still be overridden on its own.

Two knock-on changes: field-backed controls (Input, Textarea) now scale their type with size instead of holding at --manti-text-sm, so a sm input matches a sm Select beside it, and Select's rows pick up the same horizontal padding as Combobox, Menu, and Listbox rows.

Slider marks land on their values

Zag positions each marker at inset-inline-start: <percent> of the marker group, but the group's children are all absolutely positioned, so as a flex item of the control it collapsed to zero width. Every percentage resolved against 0, and the whole set of ticks piled up on a single point at the end of the track, which made marks an effectively broken prop.

The control is now a one-cell grid stack, so the track and the marker group share the same box and the markers get the track's real length to position against. Each dot is pulled back half its size on the axis Zag does not centre, and a tick the range has already passed switches to --variant-on-solid so it stays visible on the filled track. The dot size is the new --manti-slider-marker-size component token. The marker group also renders before the thumbs, so a tick at the current value no longer shows through the handle standing on it.

Arrows keep the panel hairline

Tooltip, HoverCard, and Tour bubbles draw a --manti-panel-border outline, but the arrow tip drew only a background, so the notch punched a borderless gap in that outline and read as a rendering artifact. Zag rotates the tip square 45° per side, which always leaves its top and left edges facing away from the bubble, so the hairline now goes on exactly those two and the outline runs continuously through the notch in every placement.

Tour's arrow also inherited the wrong material: an opaque surface-raised tip against a panel-tint-strong card showed up as a lighter patch stuck to its edge. It now uses the same panel tint as the card it belongs to.

Tooltip never rendered an arrow at all. The stylesheet has carried arrow rules since the component was adapted, but the React adapter skipped the part, so they were dead. Tooltip now renders the arrow like HoverCard does, behind the same showArrow prop (default true).

Popover drops its arrow

The Popover arrow drew a notch that broke the panel's silhouette: a small tinted wedge between the trigger and the top edge of the panel, with its own border seam. The panel is anchored by its offset alone, so the wedge carried no information the position did not already give.

Breaking: the showArrow prop and the arrow part are gone. The panel is arrowless in every placement.

placement is unchanged and still defaults to bottom, but it is now shown in the docs: all twelve popper placements (top, right, bottom, left, each with a -start and -end alignment) render as a live demo alongside a Storybook Placements story.

Documentation

The docs add size demos for Menu and Listbox, the twelve-placement Popover demo, a GitHub stars badge and a Theme Studio card in the shell, and refreshed logo marks. Component metadata, anatomy, token tables, theming guides, and the machine-readable project guide have been updated to match the public API.

Last updated

Built end-to-end with Manti UI components and design tokens. Manti UI is a framework-agnostic design system on Zag.js.

GitHub