settings-ui-patterns
GitHub规范 OpenChamber 设置页面的 UI 构建,定义共享组件使用、布局响应式策略及页面分组原则。防止页面结构混乱,确保视觉与交互一致性。
Trigger Scenarios
Install
npx skills add openchamber/openchamber --skill settings-ui-patterns -g -y
SKILL.md
Frontmatter
{
"name": "settings-ui-patterns",
"description": "Use when creating or modifying OpenChamber Settings pages, dialogs, controls, configuration surfaces, responsive Settings layouts, or Settings search behavior."
}
Settings UI Patterns
Required Companion Skills
- Load
theme-systemfor colors, buttons, icons, and visual states. - Load
openchamber-ui-guidancefor depth, surfaces, layout stability, sizing and composition. - Load
locale-ui-patternsfor every visible string, tooltip, placeholder, and accessible label. - Load
ui-api-decouplingwhen a setting reads/writes runtime data or adds a capability, and write the surface list from its Name The Surfaces Before Editing step before adding or moving a settings page: a page that exists on desktop and is unreachable on a phone is the common way this goes wrong.
When examples conflict, shared component/theme and localization contracts win. Stop on unresolved material conflicts.
Canonical Direction
Settings are built from the shared primitives in
packages/ui/src/components/sections/shared/SettingsSection.tsx,
SettingsPageLayout.tsx, and SettingsInfoHint.tsx. Never hand-roll page
chrome, section headers, field rows, checkbox rows, or info tooltips with raw
divs — use the primitives, and extend them (in the shared file) when a new
shape is genuinely missing.
- Flat hierarchy through spacing and typography; no boxed backgrounds or row chrome. Card grids are the one exception, for browse pages (see
references/layout.md). - Secondary helper text is hidden behind an info icon (
infoprop) by default; the default view stays quiet. - Controls have one standard size (
h-9/ selectsize="settings") and capped widths — no full-bleed inputs. - Layouts respond to the settings pane width via container queries (
@xl:/@3xl:), never viewportsm:/lg:breakpoints (the pane is much narrower than the viewport inside the dialog). - Checkbox/radio state comes before labels; selected states are subtle and never shift layout.
Keep A Page From Turning Into A List
Pages grow one control at a time, and each addition looks fine alone; the mess shows up as a whole. When adding to a page, read the page, not only the spot you add to:
- A section holds one topic a user would name ("Terminal", "Sending"). A new setting goes into the section it belongs to, or starts its own; never append it to whatever section is last or nearest.
- One row kind per run: field rows together, checkboxes together. A field row (label + select, stepper, chips) between checkboxes is the clearest sign of a page that needs regrouping.
- Same shape for the same kind of choice: a short enum is chips in a field row everywhere, never radios on one page and chips on the next.
- A text line belongs to one option and sits under its label (
description,footer), never loose between two rows. - When a page passes about four sections or a scroll of mixed topics, split it
into tabs (
references/layout.md, Pages With Tabs) rather than adding more.
Load References By Task
| Task | Required reference |
|---|---|
| Page skeleton, sections, hierarchy, nav placement, spacing, columns, responsiveness | references/layout.md |
| Field rows, checkboxes, radios, chips, selects, inputs, numeric steppers, info hints | references/controls.md |
| Adding/moving controls, pages, availability, anchors, or search entries | references/search.md |
Load each reference whose task branch applies; reference loading is complete when layout, control, and search implications are each classified.
Quick Primitive Selection
| Need | Shared primitive |
|---|---|
Page wrapper (title, description, save status, scrolling, @container) |
SettingsPageLayout |
| Titled block with divider | SettingsSection (divider={false} for the first one) |
| Label left / control right | SettingsFieldRow |
| Label above control (two-column cells, wide controls) | SettingsStackedField |
| Boolean | SettingsCheckboxRow |
| Mutually exclusive list | SettingsRadioGroup + SettingsRadioOption |
| Short segmented options | SettingsChipGroup |
| Sub-cluster with a quiet L3 title inside a section | SettingsControlGroup |
| Two-column area on wide panes | SettingsTwoColumn |
| Helper text on demand (hover + tap) | info prop or SettingsInfoHint |
Do not introduce raw <Tooltip>-based info icons, direct Remixicon components, hardcoded user-facing strings, or one-off color/button systems. New icons: reference a Remix icon name in code, then run bun run icons:generate to add it to the sprite.
Description Policy (info hints)
- Explanatory prose goes behind the info icon via the
infoprop by default. - An info hint is one or two short sentences that add what the label or summary does not say. It names no list of every action and carries no caveat that stopped being true (for example "applies after OpenCode restarts" for tools that now apply live).
- When labels alone cannot explain the differences, consequences, or conditions needed to choose a setting, use a title, a visible description, then checkbox or radio controls. Option lists whose labels already read as complete choices (large-text paste modes, send shortcut) keep the explanation behind
infoeven when it carries an exception. Having multiple options or a group title alone does not require a description; seereferences/controls.mdfor composition. - Stays visible: security/data-loss warnings, destructive consequences, required syntax/placeholder lists the user reads while typing, dynamic status, empty states, validation errors, active-flow wizard instructions.
- Mixed text: keep the warning sentence visible, move the explanation to
info.
Save Feedback
SettingsPageLayout showSaveStatus renders the shared quiet indicator: success is silent, "Saving…" appears only past ~500 ms, failures show "Save failed". Anything persisted through updateDesktopSettings reports automatically; page-specific APIs must call reportSettingsSaveState from @/lib/persistence. Never add per-page save badges or success toasts for ordinary setting writes.
Settings Search Contract
Every stable Settings control addition or move must consider search in the same change:
- explicit registry item in
packages/ui/src/lib/settings/search.tswhen searchable; - matching
data-settings-itemanchor (primitives acceptsettingsItem); - localized title/description keys;
- availability matching actual render conditions;
- when a control moves to another page, update the item's
pagetoo.
Dynamic entity rows normally are not indexed. Load references/search.md for exact rules.
Completion Criteria
- Built from shared primitives; no ad-hoc page/section/row markup.
- Description placement follows the policy above; warnings/syntax/status remain visible.
- Container-query (
@xl:/@3xl:) responsiveness — no viewport breakpoints in pane content. - Controls use the standard size and width caps; no stretched full-width inputs.
- Localized visible and accessibility text everywhere.
- Search registry, anchor, page, localization, and availability agree.
- Nearby Settings precedent and relevant tests remain consistent.
Version History
-
bf977d2
Current 2026-10-19 13:05
新增关于保持页面分组结构的指导,防止因控件添加导致页面结构混乱;更新配套技能列表以包含 openchamber-ui-guidance。
-
1f0004f
2026-09-28 05:11
新增对卡片网格(card grids)用于MCP和服务插件浏览页的指导,以及移动设备上紧凑模型行的展示规范。
-
336e192
2026-09-22 17:58
新增对 Settings API 解耦的依赖指引;更新参考文档加载策略;修正主题选择器与滚动条相关的具体实现细节。
-
2471b29
2026-09-09 11:57
优化了描述可见性指南,并统一了辅助文本的隐藏交互方式。
- 2db90f7 2026-08-20 04:55
- 74b1bd8 2026-07-25 10:37


