Skip to content

feat(ui): Mosaic Settings component - #9377

Open
austincalvelage wants to merge 6 commits into
mainfrom
austin/user-profile-02-settings-group
Open

feat(ui): Mosaic Settings component#9377
austincalvelage wants to merge 6 commits into
mainfrom
austin/user-profile-02-settings-group

Conversation

@austincalvelage

@austincalvelage austincalvelage commented Aug 10, 2026

Copy link
Copy Markdown
Member

Description

https://swingset-git-austin-user-profile-02-settings-group.clerkstage.dev/blocks/settings

Adds the composable Mosaic Settings block:

  • Adds the compound Settings.Root, Settings.Title, Settings.Group, Settings.Row, Settings.Item, Settings.Media, Settings.Content, Settings.Label, Settings.Description, and Settings.Actions interface.
  • Connects Settings.Title to the section with a generated ID and aria-labelledby.
  • Provides the standard settings surface, row separators, media placement, content layout, and trailing actions without requiring Field semantics or a field prop.
  • Supports repeated values such as multiple email addresses or phone numbers through direct Settings.Item children. The first item is the row header and subsequent items receive their nested spacing and sizing automatically.
  • Adds global and settings-specific background tokens so the surface follows global appearance changes while still supporting one-off overrides.
  • Adds Swingset examples for a complete profile, multiple email addresses and phone numbers, connected accounts, and destructive actions.

Single item:

import { Settings } from '@clerk/ui/mosaic/block/settings';

<Settings.Root>
  <Settings.Title>Account</Settings.Title>
  <Settings.Group>
    <Settings.Row>
      <Settings.Item>
        <Settings.Content>
          <Settings.Label>Name</Settings.Label>
          <Settings.Description>Preston Booth</Settings.Description>
        </Settings.Content>
        <Settings.Actions>
          <Button>Update name</Button>
        </Settings.Actions>
      </Settings.Item>
    </Settings.Row>
  </Settings.Group>
</Settings.Root>;
CleanShot 2026-08-11 at 17 41 03@2x

Multiple items:

import { Settings } from '@clerk/ui/mosaic/block/settings';

<Settings.Root>
  <Settings.Title>Account</Settings.Title>
  <Settings.Group>
    <Settings.Row>
      <Settings.Item>
        <Settings.Content>
          <Settings.Label>Email</Settings.Label>
        </Settings.Content>
        <Settings.Actions>
          <Button>Add</Button>
        </Settings.Actions>
      </Settings.Item>
      <Settings.Item>
        <Settings.Content>
          <Settings.Description>person@example.com</Settings.Description>
        </Settings.Content>
        <Settings.Actions>
          <Menu />
        </Settings.Actions>
      </Settings.Item>
    </Settings.Row>
  </Settings.Group>
</Settings.Root>;
CleanShot 2026-08-11 at 17 41 31@2x

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

@changeset-bot

changeset-bot Bot commented Aug 10, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c3954e5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Aug 10, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview Aug 12, 2026 12:48pm
swingset Ready Ready Preview Aug 12, 2026 12:48pm

Request Review

@github-actions github-actions Bot added the ui label Aug 10, 2026
@austincalvelage
austincalvelage force-pushed the mosaic-text-field-component branch from e014d4e to cfe215d Compare August 10, 2026 19:48
@austincalvelage austincalvelage changed the title User profile settings-group feat(ui):User profile settings-group Aug 10, 2026
@austincalvelage
austincalvelage force-pushed the mosaic-text-field-component branch from cfe215d to 1ef2b96 Compare August 10, 2026 22:01
@austincalvelage
austincalvelage force-pushed the austin/user-profile-02-settings-group branch from 952b17c to 4bf4850 Compare August 10, 2026 22:22
@austincalvelage austincalvelage changed the title feat(ui):User profile settings-group feat(ui): User profile settings-group Aug 10, 2026
@austincalvelage
austincalvelage force-pushed the austin/user-profile-02-settings-group branch from 4bf4850 to c3ce60e Compare August 11, 2026 16:26
@austincalvelage
austincalvelage force-pushed the mosaic-text-field-component branch from f592827 to 34b1d21 Compare August 11, 2026 16:26
@austincalvelage
austincalvelage force-pushed the austin/user-profile-02-settings-group branch from c3ce60e to a3b0bd3 Compare August 11, 2026 16:42
@austincalvelage
austincalvelage force-pushed the mosaic-text-field-component branch from 34b1d21 to c234942 Compare August 11, 2026 16:42
@austincalvelage
austincalvelage force-pushed the austin/user-profile-02-settings-group branch from a3b0bd3 to ef07a60 Compare August 11, 2026 17:25
@austincalvelage
austincalvelage marked this pull request as ready for review August 11, 2026 17:39

@maxyinger maxyinger left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

lgtm.

Heads up designs might be changing here tomorrow
https://clerkinc.slack.com/archives/C0BHNCTDZ89/p1786470840387689

An error occurred while trying to automatically change base from mosaic-text-field-component to main August 11, 2026 22:36
@austincalvelage
austincalvelage changed the base branch from mosaic-text-field-component to main August 11, 2026 22:44
@austincalvelage austincalvelage changed the title feat(ui): User profile settings-group feat(ui): Settings block Aug 11, 2026
@pkg-pr-new

pkg-pr-new Bot commented Aug 12, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@9377

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@9377

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@9377

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@9377

@clerk/electron

npm i https://pkg.pr.new/@clerk/electron@9377

@clerk/electron-passkeys

npm i https://pkg.pr.new/@clerk/electron-passkeys@9377

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@9377

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@9377

@clerk/expo-google-signin

npm i https://pkg.pr.new/@clerk/expo-google-signin@9377

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@9377

@clerk/express

npm i https://pkg.pr.new/@clerk/express@9377

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@9377

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@9377

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@9377

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@9377

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@9377

@clerk/react

npm i https://pkg.pr.new/@clerk/react@9377

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@9377

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@9377

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@9377

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@9377

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@9377

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@9377

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@9377

commit: c3954e5

@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-08-12T12:50:33.770Z

Summary

Metric Count
Packages analyzed 19
Packages with changes 0
🔴 Breaking changes 0
🟡 Non-breaking changes 0
🟢 Additions 0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on c3954e5.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Added a composable Settings component family with StyleX themes, nested-item styling, configurable elements and refs, responsive media sizes, and automatic title-based accessibility labeling. Exported the component and its types through Mosaic barrels. Added token and reset coverage tests. Added four Storybook examples, MDX documentation, registry integration, dynamic documentation loading, and Changesets metadata.

Estimated code review effort: 4 (Complex) | ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the main change: adding the Mosaic Settings component.
Description check ✅ Passed The description directly explains the new Settings component, its APIs, behavior, tokens, examples, and documentation.

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.changeset/settings-block.md:
- Around line 1-2: Update the changeset frontmatter in settings-block.md to
include an appropriate release bump for `@clerk/ui`, and add a concise release
note describing the new public Settings API.

In `@packages/swingset/src/stories/settings.mdx`:
- Around line 7-74: Reorganize the Settings compound-component page to use the
required top-level headings in order: Example, Usage, Parts, and Styling. Move
the Default story under Example, document Settings subcomponents under Parts,
and move the --cl-settings-items-gap guidance under Styling while preserving the
existing usage and example stories and the archetype required by meta.group.

In `@packages/ui/src/mosaic/block/settings.tsx`:
- Around line 149-180: Update SettingsTitle and the Settings root labeling flow
so a title ID is available during SSR, allowing aria-labelledby to reference it
before hydration when no explicit aria-label is provided; keep IDs stable
between server and client and preserve explicit labels. Add an SSR regression
test covering matching aria-labelledby and title id output.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 73fe7bf6-67e0-4c05-bc0b-15f4ede55be6

📥 Commits

Reviewing files that changed from the base of the PR and between 5e5fe0d and 5a6ccdb.

📒 Files selected for processing (12)
  • .changeset/settings-block.md
  • packages/swingset/src/components/DocsViewer.tsx
  • packages/swingset/src/lib/registry.ts
  • packages/swingset/src/stories/settings.mdx
  • packages/swingset/src/stories/settings.stories.tsx
  • packages/ui/src/mosaic/block/settings.markers.stylex.ts
  • packages/ui/src/mosaic/block/settings.test.tsx
  • packages/ui/src/mosaic/block/settings.tsx
  • packages/ui/src/mosaic/block/settings.vars.stylex.ts
  • packages/ui/src/mosaic/components/reset.test.tsx
  • packages/ui/src/mosaic/styles/index.ts
  • packages/ui/src/mosaic/tokens.stylex.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • clerk/clerk_go (manual)
  • clerk/dashboard (manual)
  • clerk/accounts (manual)
  • clerk/backoffice (manual)
  • clerk/clerk (manual)
  • clerk/clerk-docs (manual)
  • clerk/cloudflare-workers (manual)
  • clerk/clerk-ios (auto-detected)
  • clerk/cli (auto-detected)
  • clerk/clerk-android (auto-detected)

Comment on lines +1 to +2
---
---

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Add a release entry for @clerk/ui.

This PR adds the public Settings API. An empty changeset produces no @clerk/ui release or changelog entry. Add the appropriate version bump and a concise release note.

Proposed changeset
 ---
+"`@clerk/ui`": minor
 ---
+
+Add the Settings Mosaic block.

As per coding guidelines, “Use Changesets for version management and changelogs.” Based on learnings, empty changesets apply only when changes do not include functionality changes.

📝 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
---
---
---
"`@clerk/ui`": minor
---
Add the Settings Mosaic block.
---
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.changeset/settings-block.md around lines 1 - 2, Update the changeset
frontmatter in settings-block.md to include an appropriate release bump for
`@clerk/ui`, and add a concise release note describing the new public Settings
API.

Sources: Coding guidelines, Learnings

Comment on lines +7 to +74
## Usage

```tsx
import { Settings } from '@clerk/ui/mosaic/block/settings';

<Settings.Root>
<Settings.Title>Account</Settings.Title>
<Settings.Group>
<Settings.Row>
<Settings.Item>
<Settings.Media>{icon}</Settings.Media>
<Settings.Content>
<Settings.Label>Name</Settings.Label>
<Settings.Description>Shown throughout the application.</Settings.Description>
</Settings.Content>
<Settings.Actions>{control}</Settings.Actions>
</Settings.Item>
</Settings.Row>
</Settings.Group>
</Settings.Root>
```

`Settings.Group` owns the outlined surface. Its direct `Settings.Row` children own separation and may stack one or more `Settings.Item` entries. Each item lays out optional media, flexible content, and trailing actions. `Settings.Media` accepts `md` and `lg` sizes.

Use `Settings.Items` for a nested value list beneath a row's header item. The row keeps an 8px header-to-list gap, nested items stack without gaps at a 44px minimum height, and their content receives 12px vertical padding.

Override `--cl-settings-items-gap` on `Settings.Root` or a specific `Settings.Row` to customize the space between the row header and its nested value list. It defaults to 8px.

## Examples

<Story
name='Default'
storyModule={SettingsStories}
composition={[
{ name: 'Avatar', href: '/components/avatar', layer: 'Components' },
{ name: 'Button', href: '/components/button', layer: 'Components' },
]}
/>

### Multiple email addresses and phone numbers

<Story
name='MultipleEmailAndPhoneNumbers'
storyModule={SettingsStories}
composition={[
{ name: 'Badge', href: '/components/badge', layer: 'Components' },
{ name: 'Button', href: '/components/button', layer: 'Components' },
{ name: 'Icon', href: '/components/icon', layer: 'Components' },
]}
/>

### Connected accounts

<Story
name='ConnectedAccounts'
storyModule={SettingsStories}
composition={[
{ name: 'Button', href: '/components/button', layer: 'Components' },
{ name: 'Icon', href: '/components/icon', layer: 'Components' },
]}
/>

### Destructive setting

<Story
name='Destructive'
storyModule={SettingsStories}
/>

Copy link
Copy Markdown
Contributor

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 compound component page structure.

Settings is a compound component. This page starts with Usage and Examples and omits Example, Parts, and Styling.

Use Example, Usage, Parts, and Styling as the top-level headings in that order. Put Default in Example. Document subcomponents in Parts. Document --cl-settings-items-gap in Styling.

As per coding guidelines, “Compound Components pages must use the exact section order: Example, Usage, Parts, then Styling.” Based on learnings, preserve the archetype required by meta.group.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/swingset/src/stories/settings.mdx` around lines 7 - 74, Reorganize
the Settings compound-component page to use the required top-level headings in
order: Example, Usage, Parts, and Styling. Move the Default story under Example,
document Settings subcomponents under Parts, and move the
--cl-settings-items-gap guidance under Styling while preserving the existing
usage and example stories and the archetype required by meta.group.

Sources: Coding guidelines, Learnings

Comment on lines +149 to +180
const [titleIds, setTitleIds] = React.useState<string[]>([]);

const element = useRender({
defaultTagName: 'section',
render,
ref,
props: {
...mergeStyleProps(themeProps('settings'), stylex.props(reset.base, styles.root), className, style),
...rest,
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledBy ?? (ariaLabel ? undefined : titleIds.join(' ') || undefined),
},
});

return <SettingsTitleContext.Provider value={setTitleIds}>{element}</SettingsTitleContext.Provider>;
});

const Title = React.forwardRef<HTMLHeadingElement, SettingsTitleProps>(function SettingsTitle(
{ id: idProp, render, className, style, ...rest },
ref,
) {
const setTitleIds = React.useContext(SettingsTitleContext);
const generatedId = React.useId();
const id = idProp ?? (setTitleIds ? `cl-settings-${generatedId}-title` : undefined);

useSafeLayoutEffect(() => {
if (!id || !setTitleIds) {
return undefined;
}

setTitleIds(ids => (ids.includes(id) ? ids : [...ids, id]));
return () => setTitleIds(ids => ids.filter(value => value !== id));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- target outline ---'
ast-grep outline packages/ui/src/mosaic/block/settings.tsx || true
printf '%s\n' '--- target section ---'
sed -n '1,230p' packages/ui/src/mosaic/block/settings.tsx
printf '%s\n' '--- related references ---'
rg -n --glob '*.{ts,tsx}' 'SettingsTitleContext|Settings\.Title|SettingsTitle|titleIds|renderToStaticMarkup' packages/ui/src/mosaic packages/ui/src | head -250

Repository: clerk/javascript

Length of output: 12745


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- settings tests ---'
cat -n packages/ui/src/mosaic/block/settings.test.tsx
printf '%s\n' '--- safe layout effect implementation ---'
rg -n --glob '*.{ts,tsx,js}' 'function useSafeLayoutEffect|const useSafeLayoutEffect|useSafeLayoutEffect' packages/shared packages | head -120
printf '%s\n' '--- React and test setup ---'
rg -n '"react"|"react-dom"|renderToString|renderToStaticMarkup|hydrate' package.json packages/ui/package.json packages/ui/src --glob '*.{json,ts,tsx,js}' | head -200

Repository: clerk/javascript

Length of output: 12994


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- useRender implementation and call shape ---'
rg -n --glob '*.{ts,tsx}' 'export .*useRender|function useRender|const useRender' packages/headless packages/ui packages | head -80
printf '%s\n' '--- SSR test conventions ---'
cat -n packages/ui/src/mosaic/components/field/field.ssr.test.tsx
cat -n packages/ui/src/mosaic/__tests__/MosaicProvider.ssr.test.tsx
printf '%s\n' '--- source-level SSR verifier ---'
python3 - <<'PY'
from pathlib import Path
p = Path('packages/ui/src/mosaic/block/settings.tsx')
s = p.read_text()
checks = {
    'Root initializes titleIds to empty': 'React.useState<string[]>([])' in s,
    'Root derives aria-labelledby from titleIds': "titleIds.join(' ') || undefined" in s,
    'Title registration uses useSafeLayoutEffect': 'useSafeLayoutEffect(() =>' in s,
    'Title registration is not performed during render': 'setTitleIds(ids =>' not in s.split('useSafeLayoutEffect(() =>', 1)[0],
}
for name, ok in checks.items():
    print(f'{name}: {ok}')
print('Conclusion: SSR markup cannot obtain a title ID from this state/effect path.')
PY

Repository: clerk/javascript

Length of output: 5888


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- useRender server-relevant implementation ---'
sed -n '150,270p' packages/headless/src/utils/use-render.tsx
printf '%s\n' '--- generated ID and relationship patterns ---'
rg -n --glob '*.{ts,tsx}' 'React\.useId\(\)|aria-labelledby.*useId|createContext.*string|Context.*string' packages/ui/src/mosaic packages/ui/src | head -160
printf '%s\n' '--- current settings SSR coverage ---'
rg -n 'Mosaic Settings|Settings SSR|Settings\.Root|aria-labelledby' packages/ui/src/mosaic --glob '*.{test,spec}.{ts,tsx}' || true

Repository: clerk/javascript

Length of output: 11961


🌐 Web query:

HTML section element accessible name implicit region role aria-labelledby server rendered heading accessible name

💡 Result:

The HTML section element does not have an implicit landmark role [1][2]. It only functions as a region landmark (with an implicit role of region) when it is given an accessible name [3][4]. Accessible Name and Region Role The section element requires an accessible name—provided via attributes like aria-labelledby, aria-label, or title—to be exposed as a region to assistive technology (AT) [3][1][5]. Without an accessible name, the section element is treated as a generic container (like a div) and is not included in landmark navigation [5][2]. Because "region" is a generic landmark, it should be used sparingly to avoid creating "noise" in screen readers [6][5][7]. Overusing region landmarks can make it difficult for users to navigate the page effectively; therefore, developers should only define a section as a landmark when it is important enough for a user to want to navigate directly to it [6][5]. Using aria-labelledby When a section requires a name, aria-labelledby is the preferred method, especially when a visible heading already exists within the section [6][8]. By referencing the ID of that heading, you provide both a clear programmatic name and maintain consistency between the visual structure and the accessibility tree [6][9]. Server-Rendered Headings For server-rendered content, ensuring your heading elements have unique IDs and that corresponding section elements use aria-labelledby to point to those IDs is a best practice for creating robust, predictable accessibility [6][8]. While adding an accessible name to every section is technically possible, it is often discouraged if the section is not significant enough to warrant being a landmark, as unnecessary landmarks can hinder rather than help user navigation [5][7][10]. Top Results: [3] https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/ [6] https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/region_role [1] https://a11ysupport.io/tech/html/section_element [5] https://www.scottohara.me/blog/2021/07/16/section.html [4] https://w3c.github.io/wcag/techniques/html/H101 [2] https://www.stefanjudis.com/today-i-learned/section-accessible-name/ [7] https://web.dev/learn/html/headings-and-sections?hl=ar [8] https://www.w3.org/TR/WCAG20-TECHS/ARIA13

Citations:


Preserve the Settings region name during SSR.

When Settings.Root has no explicit label, Settings.Title registers its ID only in useSafeLayoutEffect. Server markup therefore omits aria-labelledby, so the <section> is not exposed as the named region available after hydration. Generate a stable title ID during render, or require an explicit root label. Add an SSR regression test for the matching aria-labelledby and title ID.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/mosaic/block/settings.tsx` around lines 149 - 180, Update
SettingsTitle and the Settings root labeling flow so a title ID is available
during SSR, allowing aria-labelledby to reference it before hydration when no
explicit aria-label is provided; keep IDs stable between server and client and
preserve explicit labels. Add an SSR regression test covering matching
aria-labelledby and title id output.

Source: Coding guidelines

Relocates the Settings compound component out of `mosaic/block` into `mosaic/components/settings`, and moves its swingset docs entry from the Blocks layer to Components.
@alexcarpenter alexcarpenter changed the title feat(ui): Settings block feat(ui): Mosaic Settings component Aug 12, 2026

@alexcarpenter alexcarpenter left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

moved this into components vs blocks. similar to like the card component for example.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/ui/src/mosaic/components/settings/settings.test.tsx (1)

9-16: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the token alias target, not only variable names.

These assertions verify that settingsVars exposes self-named CSS variables. They do not prove that settingsVars.background resolves from colorVars.background or that settingsVars.itemsGap resolves from space['2']. An incorrect source mapping would still pass. Assert the compiled StyleX declaration or the resolved CSS variable relationship.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/mosaic/components/settings/settings.test.tsx` around lines 9
- 16, Update the test around the colorVars and settingsVars assertions to verify
the compiled StyleX declaration or resolved CSS variable relationship: confirm
the settings background aliases colorVars.background and settings itemsGap
aliases space['2'], rather than asserting self-referential variable names.
Preserve coverage of both settings tokens while ensuring incorrect source
mappings fail.
🧹 Nitpick comments (1)
packages/ui/src/mosaic/components/settings/index.ts (1)

1-15: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Avoid adding a component-level re-export barrel.

As per coding guidelines, **/index.ts files should avoid barrel re-exports because they can cause circular dependencies. Move these exports to the established Mosaic entry point, or document an explicit exception if this path is required for the public API.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/mosaic/components/settings/index.ts` around lines 1 - 15,
Remove the component-level re-exports from the settings index.ts barrel, and
expose Settings and its associated types through the established Mosaic entry
point instead. If this index.ts path is required as part of the public API,
document an explicit exception rather than retaining the undocumented barrel.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/ui/src/mosaic/components/settings/settings.test.tsx`:
- Around line 9-16: Update the test around the colorVars and settingsVars
assertions to verify the compiled StyleX declaration or resolved CSS variable
relationship: confirm the settings background aliases colorVars.background and
settings itemsGap aliases space['2'], rather than asserting self-referential
variable names. Preserve coverage of both settings tokens while ensuring
incorrect source mappings fail.

---

Nitpick comments:
In `@packages/ui/src/mosaic/components/settings/index.ts`:
- Around line 1-15: Remove the component-level re-exports from the settings
index.ts barrel, and expose Settings and its associated types through the
established Mosaic entry point instead. If this index.ts path is required as
part of the public API, document an explicit exception rather than retaining the
undocumented barrel.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: e20f7233-89eb-435b-ad8b-e05237cac928

📥 Commits

Reviewing files that changed from the base of the PR and between 5a6ccdb and c3954e5.

📒 Files selected for processing (11)
  • packages/swingset/src/components/DocsViewer.tsx
  • packages/swingset/src/lib/registry.ts
  • packages/swingset/src/stories/settings.mdx
  • packages/swingset/src/stories/settings.stories.tsx
  • packages/ui/src/mosaic/components/reset.test.tsx
  • packages/ui/src/mosaic/components/settings/index.ts
  • packages/ui/src/mosaic/components/settings/settings.markers.stylex.ts
  • packages/ui/src/mosaic/components/settings/settings.test.tsx
  • packages/ui/src/mosaic/components/settings/settings.tsx
  • packages/ui/src/mosaic/components/settings/settings.vars.stylex.ts
  • packages/ui/src/mosaic/styles/index.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • clerk/clerk_go (manual)
  • clerk/dashboard (manual)
  • clerk/accounts (manual)
  • clerk/backoffice (manual)
  • clerk/clerk (manual)
  • clerk/clerk-docs (manual)
  • clerk/cloudflare-workers (manual)
  • clerk/clerk-ios (auto-detected)
  • clerk/cli (auto-detected)
  • clerk/clerk-android (auto-detected)
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/swingset/src/stories/settings.stories.tsx
  • packages/ui/src/mosaic/styles/index.ts
  • packages/swingset/src/lib/registry.ts
  • packages/swingset/src/stories/settings.mdx
  • packages/ui/src/mosaic/components/reset.test.tsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants