react/jsx-no-literals

Disallow text written directly in JSX

Text typed straight into JSX never goes through your translation function, so every user sees it in the language you wrote it in.

By default the rule only reports bare text between tags. It treats a string in braces, such as {"Bun"}, as written on purpose. The noStrings option reports those too.

Configure#

Off by default. To turn it on:

bunfig.toml
[lint.rules]
"react/jsx-no-literals" = "error" # or "warn"

Every option, set to its default:

bunfig.toml
[lint.rules]
"react/jsx-no-literals" = ["error", {
  noStrings = false,
  ignoreProps = false,
  noAttributeStrings = false,
  allowedStrings = [], # list of strings
  elementOverrides = {},
}]

Examples#

example.jsx1 problem
function Greeting() {
  return <p>Welcome back</p>;
}
example.jsxNo problems
function Greeting({ t }) {
  return <p>{t("greeting.welcome")}</p>;
}

const brand = <strong>{"Bun"}</strong>;

Options#

OptionDefaultWhat it does
noStringsfalseAlso report strings and template literals in braces, and strings in props.
ignorePropsfalseNever report anything in props.
noAttributeStringsfalseAlso report props with a plain string value, such as alt="Logo".
allowedStrings[]Strings that are never reported. Spaces around the text don't count.
elementOverrides{}Different options for some components, by name.
restrictedAttributes[]Only for an oxlint config. Props that can't have a plain string value, even with ignoreProps. bunfig.toml rejects this option.

With noStrings, braces don't help:

example.jsxwith { "noStrings": true }2 problems
function Greeting() {
  return <p title="Greeting">{"Welcome back"}</p>;
}
example.jsxwith { "noStrings": true, "ignoreProps": true }No problems
function Greeting({ t }) {
  return <p title="Greeting">{t("greeting.welcome")}</p>;
}

noAttributeStrings looks at props without the rest of noStrings:

example.jsxwith { "noAttributeStrings": true }1 problem
const logo = <img src={logoUrl} alt="Company logo" />;

allowedStrings is for punctuation and other text that's the same in every language:

example.jsxwith { "allowedStrings": ["|"] }No problems
const links = (
  <nav>
    {home} | {about}
  </nav>
);

elementOverrides#

The keys are component names, which start with a capital letter. Each value takes the options above, which replace the top-level ones for that component, plus two more:

OptionDefaultWhat it does
allowElementfalseAllow text in this component.
applyToNestedElementstrueUse these options for the elements inside the component too.
example.jsxwith { "elementOverrides": { "Trans": { "allowElement": true } } }No problems
const message = (
  <Trans>
    Welcome <b>back</b>
  </Trans>
);
example.jsxwith { "elementOverrides": { "Trans": { "allowElement": true, "applyToNestedElements": false } } }1 problem
const message = (
  <Trans>
    Welcome <b>back</b>
  </Trans>
);

An empty override resets a component to the defaults, so here it's checked without noStrings:

example.jsxwith { "noStrings": true, "elementOverrides": { "Code": {} } }No problems
const command = <Code>{"bun lint"}</Code>;

When not to use it#

If your app is in one language and stays that way, text in JSX is fine.