---
id: react/api/use-units
title: useUnits
---

The unit preference UI hook: the effective per-category unit record for the active locale, plus the validated setters. Reactive — components re-render when any unit changes.

```tsx
const { units, setUnit, resetUnit, resetAllUnits, getUnit, getUnitValues } = useUnits()
```

## Returns

### `units`

- Type: `Partial<Record<UnitCategory, string>>`
- The effective record: per-locale defaults merged with global `setUnit` overrides. Read `units.length` for the length unit — never store a unit in component state alongside this, it will disagree.

### `setUnit`

- Type: `<C extends UnitCategory>(category: C, unit: SupportedUnit<C>) => void`
- Writes a global override, validated against the category's supported values and persisted to `state`. An invalid unit is rejected, not coerced.

### `resetUnit` / `resetAllUnits`

- Type: `(category) => void` / `() => void`
- Drop one override or all of them, falling back to the per-locale defaults.

### `getUnit` / `getUnitValues`

- Type: `(category) => string | undefined` / `(category) => string[]`
- The effective unit for one category, and the allowed values for building a picker.

## Examples

```tsx
function UnitPicker({ category }: { category: 'length' }) {
  const { getUnit, getUnitValues, setUnit } = useUnits()
  return (
    <select value={getUnit(category)} onChange={(e) => setUnit(category, e.target.value)}>
      {getUnitValues(category).map((u) => (
        <option key={u} value={u}>{u}</option>
      ))}
    </select>
  )
}
```

Values passed to formatters are always in the category base unit — the unit only changes rendering, never the stored value. Mixing the two is the common mistake; the config reference draws the line.

## Next

- Rendering with units → [`useFormatter`](./use-formatter.md)
- Params vs units, the base-unit contract → [stift.config.ts](../../configuration/config-file.md)
- Headless unit state → [Formatting (vanilla)](../../vanilla/api/format.md)
