Skip to content

feat(chip): semantic variants, pill shape and a status dot - #8505

Draft
talissoncosta wants to merge 4 commits into
mainfrom
feat/chip-semantic-variants-pr
Draft

talissoncosta wants to merge 4 commits into
mainfrom
feat/chip-semantic-variants-pr

Conversation

@talissoncosta

@talissoncosta talissoncosta commented Sep 10, 2026

Copy link
Copy Markdown
Contributor
  • I have read the Contributing Guide.
  • I have added information to docs/ if required so people know about the feature.
  • I have filled in the "Changes" section below.
  • I have filled in the "How did you test this code" section below.

Changes

No issue yet — the chip consolidation still needs one raising. Related: #8465 covers the tag half.

Groundwork so the 58 legacy .chip markup sites have somewhere to go. On its own this changes
almost nothing users see; StatusBadge is the only consumer.

  • ChipVariant gains success, warning, info and muted, wired through VARIANT_UTILITIES
    as bg-surface-* + text-* token utilities, so they follow the theme with no .dark block.
  • New pill prop swaps rounded-sm for rounded-full, for status and count shapes.
  • New ChipDot (ds-chip__dot), the decorative leading dot on a status chip. aria-hidden,
    since the label carries the meaning.
  • StatusBadge rebuilt on Chip: 51 lines of bespoke SCSS deleted, the component down to a
    status-to-variant map.
  • Stories for the new variants.

Why it matters beyond StatusBadge: the legacy .chip cannot be retired while it is the only
thing that can express a solid, status or removable pill. Four shapes in that CSS
(static status, removable, solid brand, semantic status) need a variant before their call sites
can move, and this covers the semantic-status one.

ChipVariant now covers neutral, accent, solid and the five status colours
(success, warning, danger, info, muted), so batch 4 does not need a second variants PR.
danger maps to the existing surface/text danger tokens; solid is the one filled variant, on
--color-surface-action, using text-white because there is no inverse-text token yet (5.93:1,
so AA but not AAA).

The Figma tags frame is the source of truth for shape, and we were off it: it specifies a 6px
radius on a fixed 24px height
, we had rounded-sm (4px) and no explicit heights. Non-pill chips
now use rounded-md, which changes all 14 existing ds-chip call sites, and --xs states
height: 24px. --xs is the size the frame maps to: the surfaces it covers (feature rows,
TagValues) all pass the xs modifier, and the legacy .chip--xs was already 24px. The frame's
8px vertical padding is not applied — it is an artefact of a height override on the auto-layout
and would leave 8px for a 12px label.

pill is gone. Nothing in the frame is fully rounded, and the prop existed only to preserve the
--radius-full that StatusBadge.scss carried on main, which had never been checked against the
design system. Every chip is now 6px and Chip has no shape axis to get wrong. ds-chip__dot
keeps --radius-full because it is a 6px circle, not a chip.

This changes the experiment status badges from fully rounded to 6px. Deliberate, per the
frame, but it is the most visible thing in this PR.

Two things deliberately left out:

  • The second solid. The app has two filled brand pills, not one: bg-primary900 (BetaFlag,
    PlanBasedAccess) and bg-primary (UsageTab, DerivedPermissionsList, CompareFeatureRow,
    FeatureTags). solid matches the latter. Which of the two survives is a design decision, not
    a mapping, so batch 4 needs that answered first.
  • The colour derivation for user-coloured tags. That is a function rather than a variant, and
    it is where the accessibility problem in Tags optimisation #8465 actually lives.

Also unresolved: the #6606 references in Chip.tsx and Chip.scss should point at the
consolidation issue, which does not exist yet.

How did you test this code?

Static checks only so far — this needs a visual pass before merge:

  • npx tsc --noEmit: no new errors (923 on main, 923 here; the pre-existing Cannot find module 'storybook' errors also hit untouched story files).
  • npx eslint clean on the touched paths.

Still to do, and the reason this is worth a careful look rather than a rubber stamp:

  • Storybook run over the new variant stories in light and dark. Chip.stories.tsx is opted into
    Chromatic, so the CI snapshot will cover the variants themselves.
  • StatusBadge on the Experiments list across all four ExperimentStatus values (created,
    running, paused, completed) in both themes, checking the pill shape and dot match the
    bespoke SCSS this deletes. Nothing snapshots StatusBadge, so that one is manual.

@talissoncosta
talissoncosta requested a review from a team as a code owner September 10, 2026 18:05
@talissoncosta
talissoncosta requested review from kyle-ssg and removed request for a team September 10, 2026 18:05
@vercel

vercel Bot commented Sep 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
flagsmith-frontend-preview Ready Ready Preview Sep 10, 2026 8:55pm UTC
flagsmith-frontend-staging Ready Ready Preview Sep 10, 2026 8:55pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
docs Ignored Ignored Preview Sep 10, 2026 8:55pm UTC

Request Review

@coderabbitai

coderabbitai Bot commented Sep 10, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

📝 Walkthrough

Walkthrough

The shared Chip component now supports six additional variants, fixed pill corners, and ChipDot. StatusBadge maps experiment states to Chip variants and removes its custom stylesheet. Chip stories now cover solid, status, and numeric count examples.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: 🔵 Low · up to 8c173

The PR adds shared status variants and migrates StatusBadge to Chip. Current risk is low: the component documentation is slightly misleading and a stylesheet validation concern remains unresolved, but no runtime or data-impacting failure is indicated.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Docker builds report

Image Build Status Security report
ghcr.io/flagsmith/flagsmith-api-test:pr-8505 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-e2e:pr-8505 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-api:pr-8505 Finished ✅ Results
ghcr.io/flagsmith/flagsmith:pr-8505 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-private-cloud:pr-8505 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-frontend:pr-8505 Finished ✅ Results

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 83966be4-9c40-4d53-a8de-9374526e10d9

📥 Commits

Reviewing files that changed from the base of the PR and between 9180452 and 4d9d1bf.

📒 Files selected for processing (7)
  • frontend/documentation/components/Chip.stories.tsx
  • frontend/web/components/base/Chip/Chip.scss
  • frontend/web/components/base/Chip/Chip.tsx
  • frontend/web/components/base/Chip/ChipDot.tsx
  • frontend/web/components/base/Chip/index.ts
  • frontend/web/components/experiments/StatusBadge/StatusBadge.scss
  • frontend/web/components/experiments/StatusBadge/StatusBadge.tsx
💤 Files with no reviewable changes (1)
  • frontend/web/components/experiments/StatusBadge/StatusBadge.scss

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.

width: 6px;
height: 6px;
border-radius: var(--radius-full);
background: currentColor;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use the configured currentcolor keyword spelling.

Stylelint reports currentColor as a value-keyword-case error. This prevents the touched stylesheet from passing the configured lint check.

Proposed fix
-    background: currentColor;
+    background: currentcolor;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
background: currentColor;
background: currentcolor;
🧰 Tools
🪛 Stylelint (17.14.0)

[error] 31-31: Expected "currentColor" to be "currentcolor" (value-keyword-case)

(value-keyword-case)

Source: Linters/SAST tools

Comment on lines +4 to +6
const ChipDot: FC = () => <span className='ds-chip__dot' aria-hidden='true' />

export default ChipDot

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Move ChipDot into its required component folder.

The new ChipDot component does not follow the required component layout. Create ChipDot/ChipDot.tsx, co-locate ChipDot.scss, and add ChipDot/index.ts.

  • frontend/web/components/base/Chip/ChipDot.tsx#L4-L6: move the component into ChipDot/ChipDot.tsx and move its styles into ChipDot/ChipDot.scss.
  • frontend/web/components/base/Chip/index.ts#L2-L2: re-export ChipDot through the new ChipDot/index.ts barrel.
📍 Affects 2 files
  • frontend/web/components/base/Chip/ChipDot.tsx#L4-L6 (this comment)
  • frontend/web/components/base/Chip/index.ts#L2-L2

Source: Coding guidelines

@github-actions

github-actions Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor
✅ private-cloud · depot-ubuntu-latest-arm-16 — run #20352 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  1 minute, 6 seconds
commit  8c173df
info  🔄 Run: #20352 (attempt 1)

🗂️ Previous results
✅ private-cloud · depot-ubuntu-latest-16 — run #20352 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  48.9 seconds
commit  8c173df
info  🔄 Run: #20352 (attempt 1)

✅ oss · depot-ubuntu-latest-16 — run #20352 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  40.4 seconds
commit  8c173df
info  🔄 Run: #20352 (attempt 1)

✅ oss · depot-ubuntu-latest-arm-16 — run #20352 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  41 seconds
commit  8c173df
info  🔄 Run: #20352 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-arm-16 — run #20351 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  4 passed

Details

stats  4 tests across 4 suites
duration  55 seconds
commit  a234bab
info  🔄 Run: #20351 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-16 — run #20351 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  3 passed

Details

stats  3 tests across 3 suites
duration  32.6 seconds
commit  a234bab
info  🔄 Run: #20351 (attempt 1)

✅ oss · depot-ubuntu-latest-arm-16 — run #20351 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  43.1 seconds
commit  a234bab
info  🔄 Run: #20351 (attempt 1)

✅ oss · depot-ubuntu-latest-16 — run #20351 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  32.6 seconds
commit  a234bab
info  🔄 Run: #20351 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-arm-16 — run #20349 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  1 minute, 14 seconds
commit  0bfc15a
info  🔄 Run: #20349 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-16 — run #20349 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  2 passed

Details

stats  2 tests across 2 suites
duration  32.1 seconds
commit  0bfc15a
info  🔄 Run: #20349 (attempt 1)

✅ oss · depot-ubuntu-latest-arm-16 — run #20349 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  44.1 seconds
commit  0bfc15a
info  🔄 Run: #20349 (attempt 1)

✅ oss · depot-ubuntu-latest-16 — run #20349 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  2 passed

Details

stats  2 tests across 2 suites
duration  3.7 seconds
commit  0bfc15a
info  🔄 Run: #20349 (attempt 1)

@github-actions

github-actions Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Visual Regression

19 screenshots compared. See report for details.
View full report

Completes the variant set so batch 4 of the consolidation does not need a
second variants PR.

- `danger` maps to the existing surface/text danger tokens.
- `solid` is the one filled variant, on --color-surface-action. Uses `text-white`
  rather than a token because there is no inverse-text token yet; white on that
  surface is 5.93:1, so AA but not AAA.

Both get a transparent border like the other status variants, so a filled chip
keeps the same height as a bordered one beside it.

Deliberately not covered: the app has a second, darker solid (`bg-primary900`,
used by BetaFlag and PlanBasedAccess) alongside the `bg-primary` one this
matches. Which of the two survives is a design decision, not a mapping.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Figma tags frame is the source of truth and specifies a 6px radius on a
fixed 24px height. We had `rounded-sm` (4px) and no explicit heights at all.

- Non-pill chips move to `rounded-md`. Affects all 14 existing ds-chip call
  sites, which is the intent.
- `--xs` states `height: 24px` rather than deriving it from the inherited
  line-height. The frame's 8px vertical padding is not applied: it is an
  artefact of a height override on the auto-layout and would leave 8px for a
  12px label.

`--xs` is the size the design maps to; the tag surfaces the frame covers
(feature rows, TagValues) all pass the xs modifier, and the legacy `.chip--xs`
was already 24px.

`pill` keeps `rounded-full`, preserving the shape StatusBadge.scss already had
on main. That is now the only divergence from the frame's 6px, on a surface the
frame does not cover, so it is worth confirming with design.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Nothing in the tags frame is fully rounded, and the frame is the source of
truth. `pill` existed only to preserve the `--radius-full` that
StatusBadge.scss carried on main, which had never been checked against the
design system.

So every chip is now 6px. `StatusBadge` and the status/count stories drop the
prop, and `Chip` has no shape axis to get wrong.

`ds-chip__dot` keeps `--radius-full`: it is a 6px circle, not a chip.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: f75c98c4-24dd-4f22-be74-127fab2d351d

📥 Commits

Reviewing files that changed from the base of the PR and between a234bab and 8c173df.

📒 Files selected for processing (3)
  • frontend/documentation/components/Chip.stories.tsx
  • frontend/web/components/base/Chip/Chip.tsx
  • frontend/web/components/experiments/StatusBadge/StatusBadge.tsx

Included review availability: Your plan provides up to 8 included reviews per hour; 4 remain after this review.

description: {
component:
'Canonical token-based chip primitive: a small labelled pill token. Layout via Bootstrap utilities, colour/radius via token utilities, padding/sizes/border/truncation in SCSS. Leading/trailing icons go in as children. Selection lives in ToggleChip and count badges are a separate Badge concern. The legacy `.chip` (old SCSS vars + manual dark-mode block, ~35×) migrates onto this under #6606.',
'Canonical token-based chip primitive: a small labelled pill token. Layout via Bootstrap utilities, colour/radius via token utilities, padding/sizes/border/truncation in SCSS. Leading/trailing icons go in as children. `variant` covers neutral, accent, the five status colours and `solid`; `ChipDot` adds the leading dot in `currentColor`. Radius is a fixed 6px from the tags frame, so there is no shape prop. Selection lives in ToggleChip. The legacy `.chip` (old SCSS vars + manual dark-mode block, ~35×) migrates onto this under #6606.',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Replace the inaccurate “pill token” description.

The fixed 6px radius does not produce a pill shape. Change “pill token” to “chip” or “labelled token” so the description matches the component API and rendered shape.

@talissoncosta
talissoncosta marked this pull request as draft September 11, 2026 11:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request front-end Issue related to the React Front End Dashboard

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant