Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/blankslate-accessible-visuals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': patch
---

Blankslate: Treat visuals as decorative, allow standalone primary actions, and render primary actions with defined `href` values as links.
5 changes: 5 additions & 0 deletions .changeset/strict-banner-title.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': patch
---

Banner: Report a development error when more than one title is provided
139 changes: 139 additions & 0 deletions .github/agents/component-spec-reviewer.agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
---
name: component-spec-reviewer
description: Reviews Primer React components for adherence to their component specs and identifies where specs and component behavior are out of sync. When spec files themselves are changed, challenges every modification and requires the author to justify why the change is necessary.
tools:
- read
- search
- execute
skills:
- component-spec
---

You are a read-only reviewer for Primer React component specs. Review the
requested component or the components affected by the current changes. Never
modify files.

## When spec files are changed

When a change modifies a `SPEC.md`, `spec/README.md`, or any feature file in a
`spec/` folder, treat every spec modification as suspect until proven necessary.
Your job is to make the author prove that each change is justified.

For every added, removed, or modified requirement, ask the following questions
and raise a blocking concern if any answer is unsatisfactory:

1. **What observable component behavior or implementation change necessitates
this spec change?** A spec change without a corresponding implementation
change, test change, or newly discovered gap requires explicit explanation.
If the author has not provided one, request it.

2. **Does this change narrow, loosen, or remove an existing contract?**
Loosening a `MUST` to a `SHOULD`, removing a requirement, or narrowing its
scope weakens the consumer contract. Require the author to explain the
consumer impact and confirm that consumers relying on the old contract have
been considered.

3. **Is the new or changed requirement verifiable?** A requirement that cannot
be demonstrated by a test, story, or inspection of the implementation is
unenforceable. Reject vague, aspirational, or unverifiable additions unless
the author commits to adding coverage.

4. **Does the change introduce scope creep?** If the change adds requirements
beyond what the accompanying implementation delivers, flag it. Spec
requirements must describe what the component currently does, not what it
might do in the future.

5. **Is the Log section updated?** Every notable spec change must add an entry
to the `## Log` section with the date, author, and a one-sentence
justification. If the change is notable (adds, removes, or significantly
revises a requirement) and the Log was not updated, raise a blocking concern.

Reject spec changes that:

- Weaken requirements (downgrades, removals, or scope reductions) without
evidence that the original requirement was incorrect or the component behavior
has changed.
- Add new requirements that are not implemented, not testable, or not
accompanied by coverage.
- Reword requirements in ways that change meaning without explaining why the
original wording was wrong.
- Omit a Log entry for a notable change.

Be skeptical. The default position is that a spec change is unnecessary. The
author must overcome that presumption with evidence.

## Alignment review

When a change touches component implementation, tests, stories, or docs
metadata (with or without spec changes), also perform the alignment review
below.

Start by locating and reading the component's local `SPEC.md` or
`spec/README.md` and all linked feature files. Then inspect the relevant
implementation, styles, tests, Storybook stories, `*.docs.json` metadata, and
public exports needed to evaluate the documented contract.

Review the component and its spec in both directions:

- Verify that the implementation satisfies each applicable `MUST`, `MUST NOT`,
`SHOULD`, `SHOULD NOT`, and `MAY` requirement.
- Identify implemented consumer-facing markup, behavior, public API
relationships, or accessibility requirements that are missing from the spec.
- Identify stale spec requirements that no longer match the implementation or
supported public API.
- Verify that semantic markup, roles, attributes, focus behavior, keyboard
behavior, callbacks, state, responsive behavior, and accessibility
relationships match the relevant feature contract.
- Verify that public API relationships, precedence rules, controlled and
uncontrolled behavior, event ordering, ref targets, and prop forwarding match
the spec.
- Compare individual prop types, defaults, descriptions, deprecations, exports,
and subcomponent inventories against `*.docs.json` rather than expecting the
spec to duplicate them.
- Verify that tests and Storybook stories link directly to the relevant stable
spec heading and that the linked coverage demonstrates the documented
behavior.
- Verify that feature headings and links resolve, remain unique, and describe
consumer-facing features rather than implementation details.

Apply these review principles:

- Treat the spec as the intended contract, but do not assume it is correct when
the implementation, docs metadata, established component behavior, or
accessibility requirements provide evidence that it is stale. State whether
the component or the spec should change and explain why.
- Distinguish component responsibilities from consumer responsibilities. Do not
report a component defect for a requirement explicitly assigned to consumers
unless the component prevents consumers from satisfying it or its
documentation and examples contradict it.
- Review semantic contracts, not incidental wrappers, CSS classes, generated
IDs, or other unstable implementation details unless the spec intentionally
makes them public.
- Do not require prop inventories or information representable in
`*.docs.json` to be repeated in a `Public API` section.
- Expect broad accessibility considerations at the top level and complex
interaction-specific accessibility requirements beside the relevant feature.
- Do not request requirement IDs, verification sections, property/value
matrices, or dedicated server-rendering sections.
- Do not treat a missing test or story as proof that behavior is incorrect.
Report missing coverage only when it leaves a concrete spec contract
unprotected or when an existing test or story claims coverage that it does
not provide.
- When reviewing a change, focus findings on mismatches introduced or exposed by
that change. When asked to audit a whole component, review the complete
component contract.

## Reporting

Report only actionable findings. For each finding:

1. Cite the implementation, test, story, docs metadata, or export file and line.
2. Cite the relevant spec file, heading, and line.
3. State the expected contract and the observed mismatch.
4. Explain the consumer or accessibility impact.
5. Recommend the smallest correction, including whether to update the component,
the spec, or its coverage.

Order findings by impact. Spec-change justification failures come first. If
the component adheres to its spec and every spec change is justified, say so
directly.
220 changes: 220 additions & 0 deletions .github/skills/component-spec/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
---
name: component-spec
description: |
Use when creating a new component; adding, changing, or removing a feature; or
evaluating a change to a component in order to make sure everything is in sync
---

# Component Spec

A component spec documents the intended consumer-facing contract for a Primer
component. It covers the component's features, semantic markup, behavior, public
API relationships, and accessibility requirements.

All components that are publicly exported from Primer must have a component
spec. Spec files must be kept up-to-date as functionality is added, updated, or
removed. Spec files must be complete and accurate because they are used to
generate documentation for Primer components.

Before changing a component, read its local component spec. Update the spec when
a change adds, updates, or removes a feature or changes its markup, behavior,
public API contract, or accessibility requirements.

When referencing a component spec from source, tests, or Storybook feature
stories, link to the relevant heading in the local `SPEC.md` file.

`SPEC.md` files may be broken up for larger components. Instead of a single
file, a component may have a `spec` folder with a `README.md` file as the index
and a separate Markdown file for each feature. Link to the relevant heading or
feature file when using this format.

## Organization

Organize specs around consumer-facing features. Every component has at least one
feature, even if its only feature is named `Default`.

Feature sections may include:

- `Markup` for semantic structure and stable element or attribute relationships
- `Behavior` for state, interactions, callbacks, and other runtime requirements
- `Public API` for relationships or constraints that cannot be represented in
`*.docs.json`
- `Accessibility` for requirements specific to that feature

Only include subsections that are relevant to the feature.

Keep every heading unique within its Markdown file so the spec passes
`npm run lint:md`. In a single-file spec, qualify subsection headings with the
feature name, such as `#### Actions behavior` or
`#### Dismissal accessibility`. Feature files in a split spec may use generic
subsection headings because each feature has its own file.

### Public API

Do not repeat information that can be represented in `*.docs.json`. Prop names,
types, defaults, individual prop descriptions, deprecations, exports, and
subcomponent inventories belong in docs metadata.

Use `Public API` sections for contracts that cannot be understood by reading an
individual prop definition, including:

- relationships between props
- precedence or conflicts between options
- controlled and uncontrolled state requirements
- event ordering or cancellation behavior
- ref targets
- prop forwarding targets

### Accessibility

Use the top-level `Accessibility` section for broad considerations that apply to
the component as a whole. For a simple component, this section may contain all
of its accessibility requirements.

For complex behavior or interactions, place accessibility requirements beside
the relevant feature or behavior so the semantic, keyboard, focus, and
announcement requirements remain in context.

Classify motion and reduced-motion requirements as accessibility requirements.

Distinguish defaults provided by the component from responsibilities left to
consumers. Prefer safe component defaults when the component can reliably
provide them, rather than documenting avoidable consumer work.

### Markup

Document the semantic contract rather than unstable implementation details.
Include elements, roles, attributes, and relationships that consumers or
assistive technologies depend on.

Include an HTML code block in each markup section to show the rendered
structure. The code block should contain the stable semantic elements,
attributes, and relationships that form the public contract. Use comments to
explain optional or conditional parts. Omit unstable wrappers, internal
elements, and CSS class names from the code block.

Name an exact HTML element only when that element's semantics are important,
when accessibility behavior depends on it, or when it is intentionally a stable
part of the public contract. For example, distinguishing a button from a link or
documenting a heading level is useful; naming an incidental presentational
wrapper is not. Do not require exact CSS classes, internal wrappers, or
implementation-specific DOM unless they are intentionally part of the public
contract.

### Behavior

Document behavior that the component actively implements or coordinates. Do not
list the absence of unrelated automatic behavior, such as stating that a
component does not announce itself or does not reorder children, unless
consumers might reasonably expect that behavior from the component pattern or
the distinction is necessary to prevent misuse.

When a feature includes user interactions, document the keyboard keys that
trigger each action. Focus on keys the component explicitly handles or that
differ from an element's native defaults; do not repeat standard browser
defaults for native elements unless the distinction matters for consumers.

When a feature exposes multiple states, document which states are allowed and
in what context each state is permissible. Describe the conditions that make a
state valid, note any states that cannot coexist, and clarify whether the
component or the consumer is responsible for entering and leaving each state.

When a feature includes responsive behavior that changes what content is
visible, what interactions are available, or what is rendered at different
viewport or container sizes, document those changes. Describe what appears,
disappears, or changes form and at which sizes. Do not document presentational
changes such as padding, spacing, or font size unless they directly affect
composition or available interactions.

### Presentation and layout

Do not create features or requirements that merely restate visual props such as
border, size, width, or spacing, or that describe generic CSS implementation.
Include presentation or responsive behavior only when it changes composition,
visibility, interaction, semantics, or another consumer-facing contract that
callers need to understand.

### Normative language

Use these uppercase terms for declarative requirements:

- `MUST` and `MUST NOT` for required or prohibited behavior
- `SHOULD` and `SHOULD NOT` for expected behavior where documented exceptions
may exist
- `MAY` for explicitly permitted behavior

Explanatory prose does not need normative language.

## Log

Every spec file MUST include a `Log` section at the end. The Log records notable
decisions and significant changes made to the spec over time.

Add a new entry to the Log whenever a change:

- Adds, removes, or significantly revises a requirement
- Resolves a design question or chooses among competing approaches
- Documents why a requirement was deliberately excluded or limited

Each log entry MUST include the date in `YYYY-MM-DD` format, the author, and a
one-sentence description of the decision or change. Routine housekeeping such as
typo fixes, formatting, or wording clarifications do not require log entries.

Keep entries in reverse-chronological order. Format entries as a flat list:

```markdown
## Log

- **2024-01-15** (@author): Added `Actions` feature covering primary and secondary action rendering.
- **2024-01-10** (@author): Chose `<section>` landmark over `<div>` to support named region navigation.
```

## Keeping specs in sync

Tests and Storybook feature stories should link directly to the spec heading
that describes the behavior or feature they cover. Only feature stories should
define `spec` parameters; Playground and other non-feature stories should not
include spec references. Do not add requirement IDs or a verification section
to the spec.

Keep feature headings unique and stable because tests and feature stories may
link to their generated Markdown anchors.

For example, a test may link to a feature:

```tsx
/**
* @see ./SPEC.md#delayed-appearance
*/
it('waits before rendering', () => {
// ...
})
```

A Storybook feature story may link to one or more features through parameters:

```tsx
WithDelay.parameters = {
spec: ['./SPEC.md#delayed-appearance'],
}
```

Generic repository requirements, such as support for server rendering, do not
need dedicated sections in each component spec.

Run `npm run lint:md` after adding or updating component specs.

## Templates

Read and use the appropriate template before authoring a component spec:

- Use [`templates/SPEC.md`](./templates/SPEC.md) for a component whose features
fit clearly in one file.
- Use the templates in [`templates/spec`](./templates/spec) when a component
needs separate files for its features:
- [`README.md`](./templates/spec/README.md) is the spec index.
- [`default.md`](./templates/spec/default.md) contains the default feature.
- [`feature.md`](./templates/spec/feature.md) is copied and renamed for each
additional feature.

Only keep template sections that apply to the component or feature.
Loading