Inputs

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

KeyBehavior
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.
blurLeaving a segment commits the same way as (when the value is valid).

Custom props

PropTypeDescription
maxDigitsnumberMaximum digits per segment. Omit for no limit.
minNumeratornumberOptional inclusive minimum for the numerator integer (after parsing digits).
maxNumeratornumberOptional inclusive maximum for the numerator.
minDenominatornumberOptional inclusive minimum for the denominator; when omitted, the minimum stays 1 (the default unbounded behavior).
maxDenominatornumberOptional inclusive maximum for the denominator.
valuestring | nullControlled compact fraction (n/d) or empty.
onValueChange(value: string | null) => voidFires 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-fraction

This 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

00

Committed (onValueChange):

Hidden string (onChange):

Controlled value

34

Controlled value: 3/4

Shorter segments (maxDigits={3})

00

Committed:

Each segment accepts at most three digits (e.g. up to 999/999).

Segment bounds (minNumerator / maxNumerator / minDenominator / maxDenominator)

00

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

34

sm

34

default

34

lg

34