Input Fraction
Input that handles fraction entry with numerator and denominator segments and a compact value for controlled or native forms.
Overview
InputFraction composes Input Group with a fixed numerator / denominator layout (the same
segmented pattern as InputDatetime, without a calendar). A hidden input stores the compact
n/d string (e.g. 2/5) for form submission. onValueChange runs on Enter or blur
with a normalized fraction—non-negative numerator, positive denominator—or null when both
segments are cleared.
Key bindings
| Key | Behavior |
|---|---|
| ⌫ | Deletes the last digit in the focused segment. If the segment is empty, focus moves to the previous segment. |
| ⌦ | Clears the focused segment. The next digit typed replaces the whole segment (same as focusing fresh). |
| ←/→ | Move focus between numerator and denominator (at the ends of the field, the key has no effect). |
| ↵ | Commits the current segments: if they form a valid fraction, onValueChange runs with the normalized string. Works from a segment or from the surrounding control. |
| ⇥ | Moves between segments in focus order. |
blur | Leaving a segment commits the same way as ↵ (when the value is valid). |
Custom props
| Prop | Type | Description |
|---|---|---|
maxDigits | number | Maximum digits per segment. Omit for no limit. |
minNumerator | number | Optional inclusive minimum for the numerator integer (after parsing digits). |
maxNumerator | number | Optional inclusive maximum for the numerator. |
minDenominator | number | Optional inclusive minimum for the denominator; when omitted, the minimum stays 1 (the default unbounded behavior). |
maxDenominator | number | Optional inclusive maximum for the denominator. |
value | string | null | Controlled compact fraction (n/d) or empty. |
onValueChange | (value: string | null) => void | Fires when segments yield a valid normalized fraction after commit, or null when both segments are cleared. |
size | 'xs' | 'sm' | 'default' | 'lg' | Optional. Input Group size: shell height and segment padding/text scale together. This is not the HTML size attribute (that prop is not forwarded to the hidden input). |
Bounds use the same sanitizeBounds / clampNumber behavior as other numeric inputs: on blur or Enter, each segment is clamped to its range and the compact value is re-emitted. Controlled values from the parent are clamped for display so segments stay in range. Clamping applies to each integer segment, not to the fraction n/d as a single rational value.
Install
Configure your registry in components.json:
{
"registries": {
"@uxio": "https://ui.uxio.dev/r/styles/{style}/{name}.json"
}
}Then run:
npx shadcn@latest add @uxio/input-fractionThis pulls input-group as a registry dependency. The correct variant (Base UI or Radix) follows
your components.json style. The bundle includes lib/fraction-format.
Usage
Controlled value
import * as React from "react"
import { InputFraction } from "@/components/ui/input-fraction"
export function PortionField() {
const [value, setValue] = React.useState<string | null>(null)
return <InputFraction value={value} onValueChange={setValue} />
}Shorter segments (maxDigits)
import * as React from "react"
import { InputFraction } from "@/components/ui/input-fraction"
export function ShortFractionField() {
const [value, setValue] = React.useState<string | null>(null)
return <InputFraction maxDigits={3} value={value} onValueChange={setValue} />
}Segment bounds
import * as React from "react"
import { InputFraction } from "@/components/ui/input-fraction"
export function BoundedFractionField() {
const [value, setValue] = React.useState<string | null>(null)
return (
<InputFraction
minNumerator={0}
maxNumerator={5}
minDenominator={5}
maxDenominator={5}
value={value}
onValueChange={setValue}
/>
)
}Examples
Default
Committed (onValueChange): —
Hidden string (onChange): —
Controlled value
Controlled value: 3/4
Shorter segments (maxDigits={3})
Committed: —
Each segment accepts at most three digits (e.g. up to 999/999).
Segment bounds (minNumerator / maxNumerator / minDenominator / maxDenominator)
Committed: —
Numerator is clamped to 0–5 and denominator to 5 on blur or Enter (e.g. remote days out of a 5-day week).
Size variants
Use size so the field aligns with InputGroup and Input dimensions. Segment padding and text scale with the group.
xs
sm
default
lg