---
id: "packages/active-format"
title: "active-format"
description: "Formatting and parsing of dates, numbers, currency amounts, percentages and byte counts, for people and for machines."
url: "/packages/active-format"
locale: "en"
revision: "f13265b322bf0163"
---

# active-format

`@workspace/active-format` turns values into text a reader understands, and reads typed text back
into values. Every human-readable call receives its **presentation** explicitly: the reader's
language, optionally a notation profile and a time zone. Nothing is read from a provider, a cookie,
a header, the environment or a host default.

**Example: A first call**

Client: Runs entirely in your browser. Source: `examples/format/first-format.tsx`.

```tsx
// apps/docs/examples/format/first-format.tsx
'use client';

import {formatCurrency, formatDateOnly} from '@workspace/active-format';
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '@workspace/active-ui/components/primitives/table';

const LANGUAGES = ['en', 'nl', 'de'] as const;

/** The first call: the same values, the presentation passed explicitly. */
export default function FirstFormat() {
  return (
    <Table>
      <TableHeader>
        <TableRow>
          <TableHead>Language</TableHead>
          <TableHead>Calendar day</TableHead>
          <TableHead>Amount</TableHead>
        </TableRow>
      </TableHeader>
      <TableBody>
        {LANGUAGES.map((language) => (
          <TableRow key={language}>
            <TableCell className="font-mono">{language}</TableCell>
            <TableCell suppressHydrationWarning>
              {formatDateOnly('2026-12-31', language)}
            </TableCell>
            <TableCell suppressHydrationWarning>
              {formatCurrency({amount: 1234.5, currency: 'EUR'}, language)}
            </TableCell>
          </TableRow>
        ))}
      </TableBody>
    </Table>
  );
}
```

## When you use it

- You show dates, times, numbers, amounts, percentages, sizes or durations to a person.
- You read a date, a time or a number that a person typed.
- You need a machine form that never depends on language or zone (`yyyy-MM-dd`, ISO instants,
  plain dot decimals).
- You build a component or a package that formats values but must not decide the reader's language
  itself: it takes the presentation from its caller and passes it on.

## What it does not do

- **No words.** It does not translate. A component that shows text receives that text from its
  caller.
- **No language choice.** Your application decides the reader's language and passes it in. Which
  languages a product offers is your policy.
- **No hidden clock.** Only `todayIsoDate(timeZone)` and `resolveRecency` without its `now` option
  read the current time; every other function takes its moment from you.
- **No framework.** It has no React, no provider and no side effects. It runs in Node.js and in the
  browser alike.

## How it fits together

| You have | You use |
| --- | --- |
| only a language | a BCP 47 tag such as `'en'` or `'nl'` as the presentation |
| a language plus user preferences | `composePresentationContext(language, profile, timeZone)` once, and pass the result everywhere |
| a calendar day (a birthday, a due date) | `formatDateOnly`: it never shifts with a zone |
| a moment in time | `formatDate` or `formatDateTime`, in the presentation's time zone |
| an amount of money | `formatCurrency({amount, currency}, presentation)`: the currency comes from the data |
| text a person typed | `classifyDateInput`, `classifyNumberInput`, `classifyTimeInput` |
| a value for a file, an API or a URL | `formatMachineDate`, `formatMachineDateTime`, `formatMachineNumber` |

## Dependencies

`date-fns` and `@date-fns/tz`. No other workspace package, no peer dependency. Two functions need
more than an ES2022 `Intl`; see [Errors and runtime](/packages/active-format/errors-and-runtime).

## Next

- [Getting started](/packages/active-format/getting-started): receive the package and make the
  first call.
- [Presentation](/packages/active-format/presentation): the one input every formatter takes.
