Skip to main content

FUI2021: Class expression must be static

moderate

A class expression could not be read, so the classes it produces were never checked.

Details

diagnostic
{
  "code": "FUI2021",
  "ruleId": "styles/require-static-classes",
  "category": "Tokens",
  "defaultSeverity": "moderate",
  "lifecycle": "experimental",
  "fixAvailable": false,
  "evidenceRequired": true
}

Guidance

## What it means

A `className` expression produced no readable class list. The check recorded the expression and then found no resolution for it, so every class it might produce went unchecked. The finding quotes the reason it stopped, such as a computed value or an unrecognised helper.

This rule is off by default. It fires only after your project turns it on:

```ts govern: { rules: { 'styles/require-static-classes': { enabled: true, severity: 'warn' }, }, }, ```

Enabling `tailwind/unknown-class` requires the same evidence, so class validity checking reports these gaps as well.

## Why it matters

Every other class rule — palette, scale, unknown utility, arbitrary value — reads a class list. An expression nothing can read is a hole in all of them at once, and it is silent: the run looks clean because nothing was examined.

## Before

The class is assembled from a variable, so no complete class name exists in the source:

```tsx export function Status({ tone }: { tone: string }) { return <span className={"bg-" + tone}>Ready</span>; } ```

## Repair

Write complete class strings in each branch. A conditional, a logical expression, an array, an object of class keys and a template literal with whole classes around the interpolation are all readable:

```tsx export function Status({ active }: { active: boolean }) { return <span className={active ? "bg-accent" : "bg-muted"}>Ready</span>; } ```

Use a real helper rather than string arithmetic. `clsx`, the default export of `classnames`, `twMerge` from `tailwind-merge` and `cva` from `class-variance-authority` are read directly, and a local `cn` is read when its body forwards its arguments to one of them:

```tsx import clsx from "clsx";

export function Status({ active }: { active: boolean }) { return <span className={clsx("rounded-md", active && "bg-accent")}>Ready</span>; } ```

With `cva`, keep the variant table, its defaults and the selected values in source: the declared branches are read, and an unknown selection keeps the union of the reachable ones.

## A suppression is not a repair

Coverage is recomputed from the source facts on every run. Suppressing FUI2021 removes the line from the report and leaves the class expression exactly as unreadable as before, so the region still reports incomplete analysis. Make the expression readable, or accept the reported gap knowingly.

## Verify the change

Run `npx @usefragments/cli check --changed --format agent` and confirm FUI2021 is absent. Then run `npx @usefragments/cli check --changed --ci` and confirm no region reports incomplete class analysis for those files.

Intentional exception? Use a narrow, reasoned directive from the in-source exception reference.

Next steps

  • RulesThe rules that emit FUI codes.
  • ExceptionsIn-source allows and Cloud exceptions.