Skip to content
onsystemv0.6.0

Rule

no-hardcoded-radius

warning by default

Border radius must use radius tokens, not arbitrary values.

What it catches
Arbitrary radius (rounded-[7px], borderRadius: 14)
Why it matters
Corners are part of the visual language. An arbitrary radius looks almost right next to the components and never quite matches them. A warning by default.

Example

What check_ui returned for this code against the demo design system when the site was built, from version 0.6.0.

What the agent wrote
<div className="rounded-[7px] border p-4">  <Badge className="rounded-[999px]">New</Badge></div>
After the fixthe rule’s own fixes
<div className="rounded-sm border p-4">  <Badge className="rounded-full">New</Badge></div>
check_ui
  1. warning1:17fix included

    Hardcoded radius rounded-[7px] (7px) is off the scale. Nearest: rounded-sm (6px).

  2. warning2:21fix included

    rounded-[999px] (999px) is far above the radius scale, so it reads as fully rounded: use rounded-full.

How the fix is chosen

Nearest radius token (rounded-sm), including Tailwind's default keys; rounded-full (or a pill token) for values far above the scale (rounded-[999px]).

Every finding in the example carries its fix as text edits, which the agent applies, and so does eslint --fix. The code after the fix is those edits, applied.

Color matches under ΔE 0.02 count as the same color; under 0.1 the fix is offered; beyond that the message names the nearest token but leaves the choice to the agent. A fix is only offered for a token of the same hue (within 15°), or a gray for a gray, whether the color is a palette class, an arbitrary value or a literal: a pale color counts as a hue by its chroma relative to its lightness, so bg-[#fef2f2] is never swapped for a light gray that happens to be close. Status colors (destructive, warning, success, info and their foregrounds) are only offered for nearly the same hue (within 8°), never for a gray, so a brand-orange button does not become bg-destructive. Among the tokens that qualify, the one made for the utility wins: foreground and muted-foreground for text-*, fill-* and stroke-*; surfaces such as muted for bg-*; border, input and ring for border-* and ring-*. sidebar-* and chart-* tokens are only suggested in a sidebar or a chart (by file, enclosing component or classes), and so is any other family that at most one design-system file uses, such as syntax-highlighting colors or one screen's background, outside that file's components; dark: classes are compared with dark-mode values. Likewise, a spacing or radius step that is off by more than half the value (and more than 4px) is suggested but not auto-fixed. Rules that need tokens are skipped when the design system defines none of that category; a stylesheet that imports tailwindcss brings Tailwind's default spacing unit and radius scale, unless the theme resets that namespace (--spacing-*: initial, --radius-*: initial), in which case only the project's own steps are suggested. Syntax errors are reported as syntax, and so is code nested too deeply for TypeScript's parser (thousands of levels), which is then not checked.

Options

Its default severity is "warn". Set it to "off", "warn" or "error" in onsystem.config.json, or as onsystem/no-hardcoded-radius in the ESLint plugin.

Values to accept anyway, as the class or the length.

onsystem.config.json
{  "rules": {    "no-hardcoded-radius": "error"  }}

The config file covers the rest, including overrides for folders.

Suppressing a finding

When a finding is intended, a comment turns the rule off for the next line and says why after --. Checked when the site was built: the comment hides the finding on the line below it, and the others stay.

With the comment
// onsystem-disable-next-line no-hardcoded-radius -- why this one is intended<div className="rounded-[7px] border p-4">  <Badge className="rounded-[999px]">New</Badge></div>

onsystem-disable-next-line covers the next line, onsystem-disable-line its own, and /* onsystem-disable */ the rest of the file (at the top, the whole file). Without rule names they turn every rule off. A misspelled rule name is reported as a suppression warning, with the closest one, and suppresses nothing; syntax errors cannot be suppressed. For whole folders or kinds of files, such as legacy screens or generated code, use overrides in the config.