Skip to main content

modular-ds-base-components

Use when: building or evaluating unstyled Primer React primitives, especially accessibility primitives or low-level behavior that other components should build on. Covers when to create a base component instead of baking behavior into a styled component, the unstyled CSS-reset convention, deciding which parts need a base equivalent, and consolidating ARIA Authoring Practices Guide patterns.

来源信息

仓库
primer/react
最近来源活动
2026年7月28日 16:23
检测到的 SKILL.md 语言
英语
星标
3,915
分支
696

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
modular-ds-base-components
description
Use when: building or evaluating unstyled Primer React primitives, especially accessibility primitives or low-level behavior that other components should build on. Covers when to create a base component instead of baking behavior into a styled component, the unstyled CSS-reset convention, deciding which parts need a base equivalent, and consolidating ARIA Authoring Practices Guide patterns.
# Modular DS — Base Components Base components are unstyled primitives used to build higher-level components. They carry no visual styling and enforce structural accessibility constraints, similar in spirit to [Base UI](https://base-ui.com/) or [Radix Primitives](https://www.radix-ui.com/primitives). ```tsx function Example() { return ( <Dialog.Root> <Dialog.Trigger /> <Dialog.Overlay /> <Dialog.Content> <Dialog.Close /> </Dialog.Content> </Dialog.Root> ) } ``` Other examples of things suited to base components: Combobox (filtering, selection), Listbox (selection), Popover, Tabs, Treeview. Shown above with dot-notation for readability — ship flat named exports per the RSC-safe convention in `modular-ds-presentational-components`, not an `Object.assign` composed export. ## When to use a base component Use base components for accessibility primitives and low-level behaviors that need full markup and style control. Before adding custom behavior to a component, look for an existing base component, hook, or utility that can already provide the foundation — don't reimplement it. Prefer existing base primitives over recreating native elements and their reset styles. Where a component needs Primer-owned button semantics, interaction behavior, and reset styling, build on a shared primitive such as `ButtonBase` rather than hand-rolling a button reset in CSS. When you do build on a base primitive, don't pass opinionated layout props through to it unless the component's own API deliberately exposes that choice — the primitive should stay visually neutral. Accessibility primitives for established patterns (e.g. ARIA Authoring Practices Guide patterns) should be **consolidated and reused** rather than reimplemented across components. If you find yourself re-solving a pattern that already has a base component elsewhere in the repo, use it instead of writing a parallel implementation. ## What a base component covers - Structural accessibility constraints (e.g. a title must be a descendant of a dialog). - ARIA wiring via internal context, so consumers get correct semantics "for free" while retaining full markup control. - No visual opinion at all — presentational components (see `modular-ds-presentational-components`) build on top and add Primer's design tokens and layout. ## Deciding which parts need a base equivalent Not every presentational sub-part needs a base component. A base primitive earns its place when there's accessibility behavior or interactivity tied to it (e.g. a dialog root, a close control, an overlay). Purely structural parts — a label, a heading, a message wrapper — usually don't need one, since consumers can render their own markup and the surrounding base components continue to wire ARIA correctly via context. When it's not obvious whether a given part warrants its own base component, surface the decision explicitly rather than assuming. ## CSS reset convention Where a base component needs to remove browser defaults (e.g. native `<dialog>`/`<button>` styling) without adding visual opinion, ship a minimal CSS reset using `:where()` selectors so the state part of the selector contributes no specificity and consumer/presentational styles always win. Note `.Component:where([data-variant='x'])` is `0,1,0` overall, not zero — the class still counts; it's the wrapped part that stops escalating. ADR-021 proposes replacing this convention with CSS layers (`primer.components.<component-name>`, per ADR-022), but both are still 🚧 and a single `.module.css` file in the package uses `@layer` today, against dozens still using `:where()`. Follow `:where()` for now, and expect these files to be retrofitted if ADR-021 is adopted. ## Relationship to hooks Base components wrap the compound behavior hook for their component (see `modular-ds-utilities`) — they are the thin, JSX-shaped API most consumers reach for, while the hook itself stays available directly for the rarer "I need full markup control, no wrapping component at all" case. Both are first-class; a base component should not duplicate behavior that already lives in its hook. Where the hook wraps a native element with its own built-in behavior, follow the controlled component contract in `modular-ds-utilities`.
在 GitHub 查看