Skip to main content
ESLint Interlace
Plugin: react-featuresRules

jsx-no-literals

jsx-no-literals rule

Keywords: React, JSX, string literals, i18n, internationalization, translation, ESLint rule, LLM-optimized

Prevents string literals directly in JSX to encourage internationalization and consistent text management. This rule is part of eslint-plugin-react-features and provides LLM-optimized error messages.

Quick Summary

AspectDetails
SeverityWarning (i18n best practice)
Auto-Fix❌ No (requires extraction to translation keys)
CategoryReact
ESLint MCP✅ Optimized for ESLint MCP integration
Best ForInternationalized apps, consistent text management

Rule Details

Why This Matters

IssueImpactSolution
🌍 i18nCan't translate hardcoded textUse translation keys
📝 ConsistencyDuplicate strings across appCentralize text management
🔄 UpdatesHard to update text globallySingle source of truth
🧪 TestingBrittle text-based testsUse data-testid instead

Configuration

OptionTypeDefaultDescription
noStringsbooleantrueDisallow string literals in JSX
allowedStringsstring[][]Strings that are allowed (e.g., symbols)
ignorePropsbooleantrueAllow strings in prop values

Examples

❌ Incorrect

// Hardcoded text in JSX
function Welcome() {
  return <h1>Welcome to our app!</h1>;
}

// Multiple hardcoded strings
function Button() {
  return (
    <button>
      Click here to continue
    </button>
  );
}

// Text in complex components
function Card() {
  return (
    <div>
      <h2>Product Title</h2>
      <p>This is a description.</p>
    </div>
  );
}

✅ Correct

// Using translation function
import { t } from './i18n';

function Welcome() {
  return <h1>{t('welcome.title')}</h1>;
}

// Using constants
const BUTTON_TEXT = 'Click here to continue';

function Button() {
  return <button>{BUTTON_TEXT}</button>;
}

// Using react-intl
import { FormattedMessage } from 'react-intl';

function Card() {
  return (
    <div>
      <h2><FormattedMessage id="card.title" /></h2>
      <p><FormattedMessage id="card.description" /></p>
    </div>
  );
}

// Props are allowed by default
<input placeholder="Search..." />

Configuration Examples

Basic Usage

{
  rules: {
    'react-features/jsx-no-literals': 'warn'
  }
}

Allow Common Symbols

{
  rules: {
    'react-features/jsx-no-literals': ['error', {
      noStrings: true,
      allowedStrings: ['©', '•', '|', '-', '→', '←'],
      ignoreProps: true
    }]
  }
}

Strict Mode (Including Props)

{
  rules: {
    'react-features/jsx-no-literals': ['error', {
      noStrings: true,
      allowedStrings: [],
      ignoreProps: false
    }]
  }
}

Disabled for Whitespace

{
  rules: {
    'react-features/jsx-no-literals': ['warn', {
      noStrings: true,
      allowedStrings: [' ', '\n'],
      ignoreProps: true
    }]
  }
}

Migration Strategy

Step 1: Extract to Constants

// Before
<button>Submit Form</button>

// After
const SUBMIT_TEXT = 'Submit Form';
<button>{SUBMIT_TEXT}</button>

Step 2: Move to Translation File

// translations/en.json
{
  "form.submit": "Submit Form"
}

// Component
import { t } from './i18n';
<button>{t('form.submit')}</button>

Step 3: Support Multiple Languages

// translations/en.json
{ "form.submit": "Submit Form" }

// translations/es.json
{ "form.submit": "Enviar Formulario" }

// translations/ja.json
{ "form.submit": "フォームを送信" }

Further Reading

Known False Negatives

The following patterns are not detected due to static analysis limitations:

Dynamic Variable References

Why: Static analysis cannot trace values stored in variables or passed through function parameters.

// ❌ NOT DETECTED - Prop from variable
const propValue = computedValue;
<Component prop={propValue} /> // Computation not analyzed

Mitigation: Implement runtime validation and review code manually. Consider using TypeScript branded types for validated inputs.

Wrapped or Aliased Functions

Why: Custom wrapper functions or aliased methods are not recognized by the rule.

// ❌ NOT DETECTED - Custom wrapper
function myWrapper(data) {
  return internalApi(data); // Wrapper not analyzed
}
myWrapper(unsafeInput);

Mitigation: Apply this rule's principles to wrapper function implementations. Avoid aliasing security-sensitive functions.

Imported Values

Why: When values come from imports, the rule cannot analyze their origin or construction.

// ❌ NOT DETECTED - Value from import
import { getValue } from './helpers';
processValue(getValue()); // Cross-file not tracked

Mitigation: Ensure imported values follow the same constraints. Use TypeScript for type safety.