1 slot open this monthBy the makers of shadcnregistryWe built shadcnregistry. Now we build your product.Book a callCheck availability
1 slot open this monthAI features?We build AI features into your product.Book a callCheck availability
1 slot open this month🚨 Slop police🚨 Slop police: we clean up vibe-coded apps.Report itReport your app
shadcnregistry
shadcnregistry
RegistryHealthInspect
Terms of ServicePrivacy Policy
  1. Registries
  2. pulld
  3. Unit Input

Unit Input

ui

A number box with a unit beside it that settles what happens to the number when the unit changes. Reach for it wherever a form asks for a length rather than a count: a spacing, padding or radius field in a theme or design-token editor, a font-size control in a settings panel, page margins for a print or PDF export, a width or breakpoint in a layout builder, a canvas or image size, a CSS value in an admin or CMS style panel, a chart axis or gutter, a wrapper for the one CSS length a white-label tenant is allowed to set. Common asks it answers: "unit input react", "shadcn unit input", "number input with unit dropdown", "css length input react", "px rem input react", "px to rem converter component", "input with unit selector shadcn", "length field with units react", "css unit picker react", "convert px to rem in javascript", "CSS.px(16).to('rem') throws", "Cannot convert to px typed om", "CSSUnitValue to rem TypeError", "how many px is 1rem javascript", "get root font size javascript", "getComputedStyle fontSize rem base", "px rem round trip loses value", "1.06rem is not 17px", "value changes when I switch units", "unit dropdown changes my number", "width 16 not working css", "unitless length invalid css", "css unitless zero only", "input type number step per unit", "arrow key step 0.25 rem", "0.30000000000000004 spacing input", "parse 1.5rem in javascript", "split number and unit javascript", "paste 1.5rem into input", "単位付き 数値入力 react", "px rem 切り替え 入力欄", "css 長さ 入力 コンポーネント", "単位を変えたら値が変わる", "design token editor length input", "tailwind spacing scale input", "css custom property length input", "css variable px rem editor", "style dictionary token input react", "token studio px rem", "storybook control for css length", "theme editor spacing field react", "border radius input react", "letter spacing input react", "clamp value input react", "viewport unit input vw vh react", "print margin input mm inch", "デザイントークン 長さ 入力", "余白設定 px rem 切り替え". **Changing the unit is the whole component, because there are two different right answers and picking silently is what makes a field untrustworthy.** Converting keeps the rendered length and moves the number (16px becomes 1rem); reinterpreting keeps the number and moves the length (16px becomes 16rem, which renders at 256px — sixteen times bigger). Both are what somebody means, in different moments, so `behavior` names the one you want and the default converts. **It will not convert a unit it cannot account for, and that refusal is the platform's own.** Typed OM converts any fixed unit into any other — measured in Chrome 152, `CSS.px(96).to("in")` is `1in` and `.to("cm")` is `2.54cm` — and throws `TypeError: Cannot convert to px` on rem, em, %, ch, ex, lh, vw, vh, vmin and vmax, all ten of them, because a number does not know how big it is. So the fixed units convert with no help, and the relative ones convert only once `base` says what they are worth; without it the number is carried across unchanged and the field says it was carried, rather than dividing by an assumed 16 and moving a value nobody touched. The base is the caller's because it is a fact about the page, and because it is live: setting the root font-size to 20px makes `width: 1rem` compute to 20px on the next read, so a component that cached 16 would be wrong from then on. `readBase(element)` is exported to read the current ones off the document in a line. **A round trip gives back what was typed, which rounding harder does not achieve.** Over 1 to 200px against a 16px root, rounding a px→rem→px trip to 2 decimals returns the original for 50 of the 200 — 17px leaves as 1.06rem and comes back 16.96px — and against a 15px root, somebody who set `html { font-size: 15px }`, exactly 65 of 200 survive at 2, 3 and 4 decimals alike, because 1/15 does not terminate in decimal and more places never recover it. The number is therefore remembered per unit for as long as the edit lasts and restored on the way back, not recomputed; typing is a new intention and drops the memory. **A bare number is refused except as zero, which is what CSS does.** Measured, `CSS.supports("width", "16")` is false while `"0"`, `"0.0"` and `"-0"` are all true, and assigning the unitless string to `element.style.width` is a silent no-op that leaves the previous value standing — so a non-zero number with no unit is marked invalid and never posted, while `""` can still be offered in the list for the properties where it is legal (`line-height: 1.5` and `z-index: 3` both measured valid). **The arrow keys step by the unit on screen**, 1 for px and 0.25 for rem and em out of `DEFAULT_STEPS`, with Shift taking ten at once, and each step rounds to the decimals in play because ten additions of 0.1 in IEEE 754 land on 0.9999999999999999. `minPx`/`maxPx` are given in pixels so one bound means one thing in every unit; they are reported rather than silently applied while typing, and the arrow keys stop at them. Pasting `1.5rem` into the number box splits it and moves the unit, since that is how a value copied out of devtools arrives; unit identifiers are matched case-insensitively (`16PX`, `1q`) and the canonical spelling comes back. Parsing is stricter than `Number` on the reasoning this registry's number-range-input gives: `1e3`, `0x10`, `Infinity` and `1,5` are all numbers to `Number` and none of them is a length somebody typed, so they are refused and the text stays on screen to be corrected instead of being deleted out from under the reader. The two controls are one `role="group"` with a label, each separately labelled, the box is `type="text"` with `inputMode="decimal"` rather than `type="number"` — a number input discards text it cannot parse, so `16q` would vanish instead of being explained — one polite status line carries either the resolved pixel length or the problem and is wired to the box with `aria-describedby`, `aria-invalid` follows the actual fault, and a `name` posts canonical CSS (`1.5rem`) through a hidden input and posts nothing when the value is one it would not stand behind. `parseUnitValue`, `convertLength`, `resolvePx`, `toCssLength`, `stepValue` and `ABSOLUTE_PX` are exported as plain functions so the route handler that receives the string reaches the same answer the field showed. The fixed table is derived from cm the way CSS defines it rather than written out, which is also the only form that agrees with the engine bit for bit: `96/25.4` is 3.7795275590551185 in IEEE 754 where Chrome reports 3.7795275590551176. Official shadcn/ui has nothing of the kind and the measurement is not close: fetching every entry in its registry today — 65 listed, 62 fetchable, `code-block`, `questionnaire` and `trace` 404 on both style tracks — and searching all 223,287 bytes of it, `convertUnit`, `parseUnit`, `unitless`, `CSSUnitValue`, `getComputedStyle`, `fontSize`, `toFixed`, `"rem"`, `'rem'` and `unitSystem` are every one of them a zero hit; its `input` is a bare text box and `input-group` only puts ornaments either side of one, and official never reads a computed style anywhere. Within pulld it is the length end of the field family: `number-input` counts things with steppers, `number-range-input` holds a from-and-to pair, `currency-input` formats money and `duration-input` reads a span of time — each of those is one unit that never changes, and this is the one where the unit is part of the value. No dependencies beyond React and your `cn`.

pnpm dlx shadcn@latest add "https://pulld.pages.dev/r/unit-input.json"
Premium blocks for shadcn/uiShadcnblocks.com · AffiliateExplore
components/ui/unit-input.tsx