Overview of the Phoenix and LiveView Headless Number Field Component
The Mishka Chelekom Headless Number Field
ships zero opinionated styling
- only the semantic markup, full WAI-ARIA
spinbutton wiring, press-and-hold stepper buttons, optional drag-to-scrub, and
locale-aware formatting via
Intl.NumberFormat
.
Every part - scrub-area, decrement, input,
increment
and hidden-input
- is addressable through a
*_class
attribute, so you style it entirely with your own Tailwind
classes while
the accessibility and behavior keep working underneath.
Base UI Number Field example (Phoenix headless)
<.number_field id="baseui-number_field-hero" value={100} scrub_cursor class="flex flex-col items-start gap-1" scrub_area_class="cursor-ew-resize font-bold select-none" scrub_area_label_class="cursor-ew-resize text-sm font-bold text-neutral-950 dark:text-white" scrub_cursor_class="drop-shadow-[0_1px_1px_#0008] filter" group_class="flex h-8" decrement_class="flex h-full w-8 items-center justify-center border border-r-0 border-neutral-950 bg-white bg-clip-padding text-neutral-950 outline-0 select-none dark:border-white dark:bg-neutral-950 dark:text-white hover:not-data-[disabled]:bg-neutral-100 dark:hover:not-data-[disabled]:bg-neutral-800 active:not-data-[disabled]:bg-neutral-200 dark:active:not-data-[disabled]:bg-neutral-700 data-[disabled]:border-neutral-500 data-[disabled]:text-neutral-500 dark:data-[disabled]:border-neutral-400 dark:data-[disabled]:text-neutral-400" increment_class="flex h-full w-8 items-center justify-center border border-l-0 border-neutral-950 bg-white bg-clip-padding text-neutral-950 outline-0 select-none dark:border-white dark:bg-neutral-950 dark:text-white hover:not-data-[disabled]:bg-neutral-100 dark:hover:not-data-[disabled]:bg-neutral-800 active:not-data-[disabled]:bg-neutral-200 dark:active:not-data-[disabled]:bg-neutral-700 data-[disabled]:border-neutral-500 data-[disabled]:text-neutral-500 dark:data-[disabled]:border-neutral-400 dark:data-[disabled]:text-neutral-400" input_class="h-full w-[7ch] border border-neutral-950 bg-white px-2 text-left text-sm font-normal text-neutral-950 tabular-nums any-pointer-coarse:text-base dark:border-white dark:bg-neutral-950 dark:text-white focus:z-1 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white" > <:scrub_area>Amount</:scrub_area> <:scrub_cursor_icon> <svg width="26" height="14" viewBox="0 0 24 14" fill="black" stroke="white" style="display: block;"> <path d="M19.5 5.5L6.49737 5.51844V2L1 6.9999L6.5 12L6.49737 8.5L19.5 8.5V12L25 6.9999L19.5 2V5.5Z" /> </svg> </:scrub_cursor_icon> <:decrement_icon> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display: block;"> <path d="M1.5 8h13" /> </svg> </:decrement_icon> <:increment_icon> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display: block;"> <path d="M1.5 8h13M8 14.5v-13" /> </svg> </:increment_icon> </.number_field>
Parts & data attributes
Each part carries a stable
data-part
and a structural
chelekom-number_field__*
class you can target, plus root-level state attributes reflecting disabled/readonly/
required/scrubbing.
| Part | data-part | State / ARIA | Purpose |
|---|---|---|---|
| Root | root | data-disabled, data-readonly, data-required, data-scrubbing | Carries the NumberField hook; reads min/max/step/format/locale from data attributes. |
| Scrub area / cursor | scrub-area / scrub-area-cursor | data-direction, data-pixel-sensitivity | Optional drag region (e.g. a label) that scrubs the value; optional custom cursor shown while scrubbing. |
| Decrement / Increment | decrement / increment | aria-label, aria-controls, tabindex="-1" | Stepper buttons; press-and-hold to auto-repeat. |
| Input | input | aria-roledescription | The visible, locale-formatted text input. |
| Hidden input | hidden-input | aria-hidden="true", tabindex="-1" | Visually hidden type=number input carrying the raw value for form submission. |
Accessibility
Follows the
WAI-ARIA Spinbutton pattern
: Arrow Up/Down step the value by
step
(Shift for
large_step
, Alt for
small_step
), PageUp/PageDown step by the
large step, Home/End jump to min/max, and the mouse wheel can scrub the value when
focused (
allow_wheel_scrub
). The input
exposes
aria-roledescription
and the stepper
buttons carry
aria-label
and
aria-controls
.