react-data-form
Configuration & i18n
Ports, form-wide defaults, locales, currency and translation.
The library assumes no backend, no router and no visual identity. Everything that would be an assumption goes through a port, injected once at startup — and every port has a default, so a form works with no configuration at all.
configurePorts#
import { configurePorts } from "react-data-form"
import { fr } from "date-fns/locale"
configurePorts({
// How the date fields parse and format.
dateLocale: fr,
// What Intl uses for dates and amounts.
intlLocale: "fr-FR",
currency: "EUR",
components: {
// How an IRI is rendered once chosen in a dropdown.
iriLabel: ({ iri }) => <ResourceName iri={iri} />,
// Brand mark at the centre of the loader.
logo: MyLogo,
},
})| Name | Type | Default | Description |
|---|---|---|---|
dateLocale | Locale (date-fns) | US English | Parses and formats every date field, and decides the first day of the week. |
intlLocale | string (BCP 47) | the runtime's | What Intl formats dates, times and amounts with. |
currency | string (ISO 4217) | "EUR" | How PriceInputController renders an amount. The stored value stays an integer of the smallest unit. |
components.iriLabel | FC<{ iri?, property? }> | the raw identifier | Turns /api/authors/4 into a name in a dropdown. Configure it once and every choice field in the application reads. |
components.logo | FC | nothing | Brand mark shown at the centre of the loader. |
It merges
Calling configurePorts twice merges rather than replaces, down to individual components — so a test can override one port without restating the rest.
setFormConfig#
Ports are about the environment; setFormConfig is about the forms themselves. It sets the description every form starts from, so a default applied here needs no repetition.
import { setFormConfig } from "react-data-form"
setFormConfig({
defaultForm: {
label: {
success: "Saved",
error: "Some fields need another look",
},
components: {
// Every form in the application, unless it says otherwise.
formSubmitAction: MySubmitBar,
},
},
})It deep-merges into the existing configuration, and the shipped defaults already name the standard components — replacing one leaves the others in place.
Translation#
Every label, description and button caption passes through react-mini-i18n, so your application and the library translate from one dictionary.
import { setTranslation, Trans, translate } from "react-mini-i18n"
setTranslation({
"First name": "Prénom",
"Save": "Enregistrer",
})
// Labels go through it automatically; your own components can too.
<Trans>First name</Trans>
translate("Save")- Keys are the source strings, so an untranslated label falls back to itself rather than to a missing-key marker.
- The dictionary is a module-level singleton, which is why the package is a peer dependency — see Installation.
Server rendering#
Both the ports and the dictionary are process-level singletons, so a server-rendered application has to configure them on the server as well as in the browser. Do it at module scope, in a file both entry points import.
// A singleton is per-process, so configure once, at module scope, on both
// sides — a server render that skipped it would emit US dates the browser then
// disagrees with.
configurePorts({ intlLocale: "fr-FR", currency: "EUR" })This site does exactly that
It runs on TanStack Start, configures both libraries once from a module imported by the root route, and renders the prose on the server while mounting the live examples in the browser.