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

Application integration

Cascade layers and application resets

Manti styles live in cascade layers. Unlayered application CSS wins regardless of selector specificity, so a broad reset such as button { padding: 0 } can erase the geometry of Button, ToggleGroup, Menu, and other button-backed anatomies.

Import Manti before application CSS and keep native resets away from Manti parts:

button:not([data-scope][data-part]) {
  padding: 0;
}

When overriding anatomy, prefer low-specificity selectors:

:where([data-scope='button'][data-part='root']).compact-action {
  --manti-button-height: var(--app-compact-control-height);
  --manti-button-padding-x: var(--app-compact-control-padding);
}

Component variables define control geometry. Setting only height does not override a component's token-backed min-height.

Focus ownership

Input and Textarea put the visible focus treatment on the outer control part; the native input is intentionally outline-free. If an existing search shell or composite widget already paints focus, use focusRing="none" and keep one visible owner:

<SearchShell>
  <Input aria-label="Search" focusRing="none" />
</SearchShell>

Do not remove both focus indicators. Global input:focus-visible rules should either exclude Manti field inputs or be placed in a controlled layer.

Inline SVG

Manti's reset makes SVG replaced media block-level. Wrap application icons or restore inline flow for text-adjacent SVG:

.app-inline-icon {
  display: inline-block;
  vertical-align: middle;
}

Button's leadingIcon and trailingIcon slots already render inside inline-flex anatomy parts.

Vitest and jsdom

Zag/Floating UI components expect PointerEvent and ResizeObserver. Add small test-environment shims when jsdom does not provide them:

class ResizeObserverMock implements ResizeObserver {
  observe() {}
  unobserve() {}
  disconnect() {}
}

globalThis.ResizeObserver ??= ResizeObserverMock;
globalThis.PointerEvent ??= MouseEvent as typeof PointerEvent;

Test pointer, keyboard, and direct click activation independently for menus and other composite controls.

Native forms

Manti fields compose with the platform form element; a state-owning Form primitive is not required:

<form onSubmit={handleSubmit}>
  <Input name="email" label="Email" required />
  <Button type="submit">Save</Button>
</form>

Use requiredIndicator={null} when native required semantics should remain without a visual marker.

Combined local date and time

For a single native local datetime value, Input remains the smallest contract:

<Input type="datetime-local" name="endsAt" label="Ends at" />

When product requirements need separate DatePicker and TimePicker surfaces, place both under one visible field label and combine their values in application state. Keep one accessible group name and one validation message.

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