Skip to content

Components

A component is a named DOM subtree, identified by one or more CSS selectors. Names replace the generic accessibility role in enriched snapshots, so an agent reading the page sees DepartureDatePicker instead of group.

- name: DepartureDatePicker
selector: '[data-picker="departure"]'
source: src/components/DatePicker.tsx
children:
- name: date-input
selector: input
- name: day
selector: '[role="gridcell"]'

name and selector are required. See Schema reference for the full field list, including description, source, and memory.

selector accepts a single CSS selector string or an array of strings:

# Single selector
- name: SubmitButton
selector: 'button[type="submit"]'
# Array — alternates tried in order, first match wins
- name: SearchInput
selector:
- '[data-component="SearchInput"]'
- 'input[type="search"]'
- '#search'

Use the array form when you want a stable name across multiple variants of the UI — a redesigned page, a feature flag, or a third-party widget you don’t control. The array isn’t an OR over all matches; the runtime takes the first selector that matches anything and stops.

If a selector matches multiple elements, all matches get the name. Selectors are not required to be unique.

The recommended pattern is to render a data-component="<Name>" attribute on the root element of each named component, then select on that attribute:

<nav data-component="Navigation"></nav>
- name: Navigation
selector: 'nav[data-component="Navigation"]'

This decouples the sightmap from class names, CSS modules, and styling refactors. It costs one attribute per named component and is trivial to grep for.

It is a convention, not a requirement. Any CSS selector works.

Selectors inside children are evaluated within their parent’s matched subtree, not against the whole document. This is how the spec avoids naming collisions between, say, two card components that each contain a button.primary.

- name: SearchCard
selector: '[data-component="SearchCard"]'
children:
- name: submit
selector: 'button.primary' # only inside SearchCard's subtree
- name: BookingCard
selector: '[data-component="BookingCard"]'
children:
- name: submit
selector: 'button.primary' # only inside BookingCard's subtree

Components at the file root are global — matched on every view. Nested inside a view, they are scoped to that view. Both forms are additive: a view sees its own components plus all globals. See Views for the full rule.

When the same component (a site header, a persistent footer, a chat widget) appears across many views, a components: array entry can be a reference object instead of a fresh inline definition:

- $ref: SiteHeader

The reference is expanded inline to a deep copy of the named component before matching. Names resolve against a registry built from the root-level components: of every loaded file — nested children and view-scoped definitions are not addressable.

# .sightmap/components.yaml — definitions
components:
- name: SiteHeader
selector: '#site-header'
children:
- name: SearchBox
selector: 'form#header-search'
# .sightmap/views/plp.yaml — view-scoped, attests its expected globals by reference
views:
- name: PLP
route: /b/**
components:
- $ref: SiteHeader # attests SiteHeader is expected on this view
- name: ProductGrid # view-specific
selector: '[data-component="ProductGrid"]'

Two reasons to prefer $ref over inline duplication or implicit auto-match:

  • Single source of truth. Update the header’s selector or memory entries in one place; every referencing view picks up the change.
  • Attestation. A view’s components: becomes a compact, machine-readable manifest of what it expects to see. Drift-detection tooling can surface “attested but matched 0 elements” as a signal — distinct from “this name was never mentioned anywhere.”

A $ref entry MUST contain exactly one key ($ref); overrides are not allowed in v1. See the schema reference for conformance rules, recursive expansion, and the dedup behavior when a view-scoped $ref and a file-root global share a name.

A component can declare additional files whose changes should prompt re-curation of the entry — typically style modules, hooks the component consumes, or shared utilities that don’t warrant their own entry:

- name: ListCard
selector: '[data-component="ListCard"]'
source: src/components/ListCard.tsx
dependencies:
- src/components/ListCard.module.css
- src/hooks/useCardActions.ts

dependencies is purely curation-time metadata — runtime adapters never read source files. Strings are minimatch globs, project-root-anchored, with !-prefix negation. See the schema reference for what belongs and what does not.

Requests for API endpoints. Memory for the freeform notes you can attach to any component.