@spark-web/design-system
Version:
--- title: Design System ---
144 lines (100 loc) • 5.3 kB
Markdown
# Internal admin — interaction and pattern rules
These rules apply to all components and patterns built for internal admin
surfaces. They sit above individual component rules. When a conflict exists
between these rules and a component-level CLAUDE.md, these rules take precedence
for admin surfaces.
---
## Row interaction rules
### Clickable rows
A row is clickable when the data model has a record-level detail view or
destination page. The agent must determine this from the PRD:
- If the PRD describes a detail page, record view, or drill-down → row is
clickable
- If the PRD describes a read-only data display with no record destination → row
is not clickable
- If unsure, default to clickable
### Hover state
Hover state is determined entirely by whether the row is clickable:
- Row is clickable → hover state is applied when the cursor is over the row,
**except** when hovering a button within the row (e.g. the MeatballMenu
trigger)
- Row is not clickable → hover state is never applied, no exceptions
When a clickable row contains a MeatballMenu, the row hover must be suppressed
while the cursor is over the meatball button. DataTable implements this
automatically when `enableClickableRow` is set — see `@spark-web/data-table`
CLAUDE.md.
---
## Overflow menu rules
An overflow menu on a row is used only when ALL of the following are true:
- There are 2 or more actions that apply to the row record
- The actions relate only to that specific record, not to the page or table
Use this decision tree:
```
Does the row have actions?
No → no overflow menu, no action column
Yes → how many actions?
1 action + row is NOT clickable → inline button or icon
1 action + row IS clickable → overflow menu
2+ actions → always overflow menu
```
Never place inline action buttons alongside a clickable row.
---
## Badge and pill rules
A badge or pill is used only when:
- The field represents a status with 2 or more distinct values
- The status values have meaningful visual distinction (e.g. active vs inactive,
pending vs approved vs rejected)
Do not use a badge when:
- The field is free-form text
- The field is a boolean with no meaningful status distinction
- There is only one possible value
### Badge tone mapping
This mapping is authoritative for the internal-admin surface. If a component
CLAUDE.md defines tone guidance, the mapping below takes precedence.
Map status values to tones using this logic derived from the PRD:
- Positive / active / approved / complete → `positive` tone
- Warning / approaching limit / expiring → `caution` tone
- Critical / rejected / failed / overdue / suspended → `critical` tone
- Neutral / inactive / archived / unknown → `neutral` tone
- Pending / in review / awaiting approval → `info` tone
**Caution vs info (pending):** Use `caution` for warnings that are
time-sensitive or approaching a limit. Use `info` for states where a record is
waiting on a human decision or review (e.g. "Pending approval", "Under review").
Component choice:
- Always use `<Badge>` (dot + label) for status columns in list-page tables —
never `<StatusBadge>`
- Use `<StatusBadge>` (colored pill, no dot) only in page headers and section
headers via their `statusBadge` prop — never in table status columns
Available tones for both components:
`accent | caution | critical | info | neutral | positive`. There is no `pending`
tone — always use `info` for pending/awaiting states.
When in doubt, use `neutral`. Never invent a tone that does not exist in the
Spark Web theme.
---
## Destructive-action caution alert
When a form control triggers a destructive or irreversible side-effect (e.g.
toggling off an authority contact, revoking access), show an
`Alert tone="caution"` **below** the control that caused the change — not above
it. The alert appears only while the destructive state is active, and disappears
when the user reverses the action (e.g. re-toggles the item back on).
Place the alert after the controls so the user sees the change they made before
the warning. Showing it above shifts the layout downward and pushes the controls
away from where the user just clicked.
---
## Button size
Internal-admin surfaces are dense, so the compact `size="small"` button (32px
tall) is permitted here — use it for inline row actions, table toolbars, and
other tightly-packed action clusters where the default `medium` button would
crowd the layout.
Use `size="small"` only where density genuinely requires it. Page-level primary
actions (page headers, form submit/cancel) stay at the default `medium`. Never
mix `small` and `medium` buttons within the same action group — pick one size
per cluster. The `small` size is scoped to internal-admin; do not use it on
vendor-admin or public surfaces.
---
## Rules that update as the system grows
When a new pattern or component is added to the internal admin surface, update
this file with any new interaction rules that apply globally. Do not duplicate
rules that already exist here in component-level CLAUDE.md files. If a new
pattern file is added, also update the feature-type table in
`node_modules/@spark-web/design-system/patterns/CLAUDE.md` in the same commit.