Getting started
Receive active-format in your repository, declare it, and make the first call.
@workspace/active-format 1.0.0Developmentunreleased, in development in Foundationbaseline ce081dc3
These steps were carried out in a new, empty repository with a React app on Vite, through the managed transfer, without any path to Foundation or to the source repository.
Prepare your repository#
A pnpm workspace with
packages/*, Node.js 26, and byte-exact checkouts for transferred packages:yaml# pnpm-workspace.yamlpackages: - packages/* - apps/*Text# .gitattributespackages/** -textReceive the package#
active-formatcan be requested on its own: it depends on no other workspace package. Ask the source repository for a bundle ofactive-format(on thedevelopmentchannel while it is unreleased), then follow Receiving packages:Terminalnode tools/rps/rps-apply.mjs plan --bundle <bundle-folder> --developmentnode tools/rps/rps-apply.mjs apply --bundle <bundle-folder> --expect-plan <digest> --developmentThe package now sits in
packages/active-format. Do not edit it there.Declare, install and verify#
In the
package.jsonof the app that uses it:JSON{ "dependencies": { "@workspace/active-format": "workspace:*" }}Terminalpnpm installThen prove that your app resolves the managed copy:
Terminalnode tools/rps/rps-apply.mjs verify-install --from <app-folder>The output must list
@workspace/active-formatascurrent. If it lists no package, nothing was checked: the declaration or the installation is missing.The package ships TypeScript source. Vite compiles it as it is. In a Next.js app, add it to
transpilePackagesinnext.config:JavaScriptconst nextConfig = { transpilePackages: ['@workspace/active-format'],};The first call#
TypeScriptimport { classifyNumberInput, composePresentationContext, formatCurrency, formatDateOnly, toIanaTimeZone,} from '@workspace/active-format'; formatDateOnly('2026-12-31', 'nl'); // '31 dec. 2026'formatCurrency({amount: 1234.5, currency: 'EUR'}, 'nl'); // '€ 1.234,50' const presentation = composePresentationContext( 'en', {dateFormat: 'DMY_NUMERIC'}, toIanaTimeZone('Europe/Amsterdam'),);classifyNumberInput('1234.56', presentation).number; // 1234.56// A grouping separator is refused while typing and accepted when pasted:classifyNumberInput('1,234.56', presentation).status; // 'invalid'classifyNumberInput('1,234.56', presentation, {mode: 'paste'}).number; // 1234.56The same calls, running in your browser:
A first callClient
Language Calendar day Amount en 31 Dec 2026 €1,234.50 nl 31 dec. 2026 € 1.234,50 de 31. Dez. 2026 1.234,50 € Full source examples/format/first-format.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> );}Check the runtime#
If you call
formatCurrencywith exact decimal strings orformatElapsedDuration, check that your runtime supports them; see Errors and runtime.
Next#
Read Presentation before you pass a presentation through your own components.