Ask your question and get a summary of the document by referencing this page and the AI provider of your choice
Version History
- "Release of the variants feature"v9.0.06/12/2026
- "`variant` now accepts a string or an object — the former `meta` / dynamic records are declared as object variants"v9.1.06/26/2026
- "A variant declares only the keys it overrides; undeclared variants fall back to the default entry"v9.1.17/31/2026
- "Providers accept an ambient `variant` prop; selectors accept an ordered preference chain"v9.1.28/4/2026
If you have an idea for improving this documentation, please feel free to contribute by submitting a pull request on GitHub.
GitHub link to the documentationCopy doc Markdown to clipboard
Variants
A variant is a set of content files that share the same dictionary key but each carry a different variant value. Intlayer serves the appropriate file based on the selector passed to useIntlayer.
The variant value can take two forms:
- A string — a single named alternative (A/B tests, seasonal banners, feature flags).
- An object — a structured discriminator addressed by a set of fields (CMS records, user-specific copy, any content keyed by an opaque ID). The whole object is the identity: the selector must provide an equal object to resolve the entry.
The object form replaces the formermetafield. Anywhere you previously wrotemeta: { id, … }, writevariant: { id, … }, and select it with{ variant: { id, … } }.
Named (string) variants
Each file represents one named alternative. Omitting variant (or setting it to "default") marks it as the fallback.
Copy the code to the clipboard
import { t, type Dictionary } from "intlayer";
const dictionary = {
key: "hero-banner",
variant: "default",
content: {
headline: t({
en: "Build faster with Intlayer",
fr: "Développez plus vite avec Intlayer",
}),
cta: t({ en: "Get started", fr: "Commencer" }),
},
} satisfies Dictionary;
export default dictionary;Copy the code to the clipboard
import { t, type Dictionary } from "intlayer";
const dictionary = {
key: "hero-banner",
variant: "black_friday",
content: {
headline: t({
en: "50 % off — today only",
fr: "−50 % — aujourd'hui seulement",
}),
cta: t({ en: "Shop now", fr: "Acheter maintenant" }),
},
} satisfies Dictionary;
export default dictionary;Partial variants
A variant declares only the keys it overrides; the rest are inherited from the default entry.
Copy the code to the clipboard
import { t, type Dictionary } from "intlayer";
const dictionary = {
key: "hero-banner",
variant: "summer",
content: {
headline: t({
en: "Build faster all summer",
fr: "Développez plus vite tout l'été",
}),
},
} satisfies Dictionary;
export default dictionary;Copy the code to the clipboard
useIntlayer("hero-banner", { variant: "summer" });// → { headline: "Build faster all summer", cta: "Get started" } — `cta` inheriteduseIntlayer("hero-banner", { variant: "never-declared" });// → the default entrySo you only add a variant file where the wording actually differs. A key resolves to null only when it declares variants but no default entry.
Consuming named variants
Default variant
Copy the code to the clipboard
import { useIntlayer } from "react-intlayer";
export const Hero = () => {
const { headline, cta } = useIntlayer("hero-banner");
// → default variant
return (
<section>
<h1>{headline}</h1>
<a>{cta}</a>
</section>
);
};Named variant
Copy the code to the clipboard
const { headline, cta } = useIntlayer("hero-banner", { variant: "black_friday",});Named variant with explicit locale
Copy the code to the clipboard
const content = useIntlayer("hero-banner", { variant: "black_friday", locale: "fr",});Object (structured) variants
An object variant addresses content by an arbitrary set of key-value pairs declared in the variant field — making it possible to model CMS records, user-specific copy, or any content whose key is an opaque ID. The whole object is the identity: the selector must provide an equal object for the entry to resolve.
Copy the code to the clipboard
import { t, type Dictionary } from "intlayer";
const dictionary = {
key: "product",
variant: { id: "prod_abc", userId: "user_123" },
content: {
name: t({ en: "Widget Pro", fr: "Widget Pro" }),
description: t({ en: "The best widget.", fr: "Le meilleur widget." }),
},
} satisfies Dictionary;
export default dictionary;Copy the code to the clipboard
import { t, type Dictionary } from "intlayer";
const dictionary = {
key: "product",
variant: { id: "prod_abcd", userId: "user_123" },
content: {
name: t({ en: "Widget Lite", fr: "Widget Lite" }),
description: t({ en: "A lighter option.", fr: "Une option plus légère." }),
},
} satisfies Dictionary;
export default dictionary;Consuming object variants
Pass the matching object to variant. Every field declared on the dictionary must be provided and equal; otherwise the result is null. Field order does not matter.
Copy the code to the clipboard
import { useIntlayer } from "react-intlayer";
export const Product = ({
productId,
userId,
}: {
productId: string;
userId: string;
}) => {
const content = useIntlayer("product", {
variant: { id: productId, userId },
});
if (!content) return null;
return <p>{content.description}</p>;
};With explicit locale
Copy the code to the clipboard
const content = useIntlayer("product", { variant: { id: "prod_abc", userId: "user_123" }, locale: "fr",});Missing field — no match
Copy the code to the clipboard
// Returns null: `userId` is missing, so the object does not match the declared variantconst content = useIntlayer("product", { variant: { id: "prod_abc" } });Ambient variant
Some variant dimensions are fixed for a whole session — the tenant, the school type, the plan tier. They are resolved once, and no component should have to pass them by hand.
Do not wrapuseIntlayerin your own hook to inject them. The build-time optimization only rewrites a literaluseIntlayer("key")imported from the framework package, so nothing behind a wrapper gets bundled.
Declare the variant once on the provider instead, exactly like locale:
Copy the code to the clipboard
import { IntlayerProvider } from "react-intlayer";
export const App = ({ locale, schoolType }) => (
<IntlayerProvider locale={locale} variant={schoolType}>
<Hero />
</IntlayerProvider>
);Every dictionary read below the provider now resolves against that variant, and a call-site selector always wins:
Copy the code to the clipboard
useIntlayer("hero-banner");// → the provider variantuseIntlayer("hero-banner", { variant: "summer" });// → "summer" — replaces the provider variant, it is not extendedForms
The variant prop accepts three forms:
Open the table in a modal to view all data content clearly
| Form | Meaning |
|---|---|
variant="school1" | one named variant for every key |
variant={["school1", "default"]} | an ordered preference chain |
variant={{ "hero-banner": "school1", default: "base" }} | one variant per dictionary key |
Preference chain
A chain is tried left to right against the entries each key declares, and the first declared one wins. When none is declared, the implicit default entry is used — exactly as for a single value.
Copy the code to the clipboard
<IntlayerProvider variant={["school1", "school2"]} />// `hero-banner` declares no `school1` entry but declares `school2` → "school2"// a key declaring neither → the default entrySo ["black_friday", "summer"] reads as "black friday if this key has one, else summer, else default". Chains are also accepted at the call site:
Copy the code to the clipboard
useIntlayer("hero-banner", { variant: ["black_friday", "summer"] });Note this is the mirror image of the array accepted by the variant field of a content file: there an array declares one entry per element, here it consumes them in priority order.
Per-key map
Address each dictionary key separately. The reserved default entry covers every key not listed:
Copy the code to the clipboard
<IntlayerProvider variant={{ "hero-banner": "school1", product: ["school1", "default"], default: "base", }}/>On a provider a plain object is always read as the per-key map, never as an object variant — the two are structurally identical. To pin an object variant globally, nest it under an entry: variant={{ default: { id: "prod_abc" } }}.
Because the map's keys are checked against your declared dictionary keys, a typo — or an object variant written directly, such as variant={{ id: "prod_abc" }} — is a compile-time error.
Loading mode
Object variants are often loaded lazily. Set importMode on the dictionary to control this:
Copy the code to the clipboard
const dictionary = {
key: "product",
importMode: "fetch", // or "dynamic"
variant: { id: "prod_abc", userId: "user_123" },
content: { … },
} satisfies Dictionary;
export default dictionary;See bundle optimization for details on static, dynamic, and fetch modes.
Typical use-cases
- A/B copy tests driven by an experiment key
- Seasonal or promotional banners
- Feature-flagged messaging
- Locale-specific marketing campaigns
- Per-product marketing copy managed in a CMS
- User-specific or account-specific content
- Any content keyed by an opaque runtime ID