Skip to content
Sidebar Configuration
AutoXXS (320px)XS (375px)SM (640px)MD (768px)LG (1024px)XL (1280px)XXL (1536px)
SketchMaterialiOSTamagui
DataInjectionKeyPatternsServiceTransactionProcessResearchProductQualityPerformanceSpecDomainFunctionTechnologyArchitectureConfigMiddlewareDataDatabaseDrizzleMigrationModelop-sqliteSchemaSQLState ManagementDraftKeystoneMergePatchPatchesPersistenceReactiveRedoStoreUndoTestingDeviceFactoryIsolationTypeScriptZodTopicsCommunicationBidsNVCDesignDesign ImplicationsEducationPedagogyFoundationsPsychologyAttachmentFloodingRelatingAuthentic RelatingUIEditorReact Native

Sidebar Configuration

The sidebar is configured entirely in starspec.config.js via the sidebar.entries array. Each entry is a triplet that maps a processor ID to a section/group path with optional display overrides.

Triplet syntax

[id, 'Section/Group', opts?]
PositionTypeDescription
idstringTag-processor tag name or aggregate-processor id (see reference below)
pathstring'Section' places the entry directly in a section. 'Section/Group' nests it in a named sub-group. '' (empty) places it at the sidebar root with no section wrapper.
optsSidebarEntryOptsOptional overrides (see below)

Options (SidebarEntryOpts)

OptionTypeDefaultDescription
labelstringProcessor-definedOverride the display label (static)
collapsedbooleantrueWhether the group starts collapsed
groupByDomainbooleanfalseCreate sub-groups per domain
groupByCategorybooleanfalseCreate sub-groups per category
linkstringStatic link (bypasses processor resolution)
filter(entry: SidebarEntryContext) => booleanExclude entries; return true to keep
mapLabel(entry: SidebarEntryContext) => stringCompute display label from entry data
sort(a: SidebarEntryContext, b: SidebarEntryContext) => numberAlphabeticalCustom sort comparator

Entry hooks

The three function hooks — filter, mapLabel, and sort — let you dynamically control which entries appear, how they are labelled, and in what order. All three are optional and independent; use any combination.

Pipeline order: filtersortmapLabel. Labels are mapped last so that sort can compare on original labels when needed.

When a custom sort is provided, the default alphabetical sort within domain and category groups is skipped — entries preserve the order established by the pipeline.

The hooks receive a SidebarEntryContext:

interface SidebarEntryContext {
id: string; // document slug (last segment of link path)
label: string; // resolved display label
link: string; // URL path, e.g. '/features/export-data'
domain?: string; // domain slug
category?: string; // category slug
status?: string; // frontmatter status (draft, pending, ready, qa, done, published)
}
Using filter, sort, and mapLabel to customise the Features sidebar group
sidebarconfighooks sidebar-entry-hooks
const STATUS_ORDER = { ready: 0, qa: 1, done: 2, pending: 3, draft: 4 };
['feature', 'Specification/Features', {
groupByDomain: true,
filter: (e) => e.status !== 'draft',
sort: (a, b) => STATUS_ORDER[a.status] - STATUS_ORDER[b.status],
mapLabel: (e) => `${e.status === 'done' ? '' : ''} ${e.label}`,
}],

Ordering rules

  1. Section order is determined by first appearance in the entries array. The first entry mentioning 'Specification' determines where that section appears relative to others.
  2. Entry order within a section follows array position.
  3. Only listed entries appear. Omitting an ID hides it from the sidebar.
  4. Multiple entries sharing the same Section/Group path merge into one group.

Sections

Six sections are available:

SectionDefault collapsedDescription
ProductfalseProduct-level views: manifest, glossary, roadmap, tours, tags
JournalfalseArticles, quotes, knowledge base, bibliography
SpecificationfalseRoles, domains, stories, features, flows, designs
ReferencetrueCross-cutting aggregate pages
ImplementationtrueBlueprints, component registry
StarSpecAuto-populated from instruction documents (configurable via sidebar.starspec)

Special entries

  • Changelog: Appended automatically at the end when changesets exist. No entry needed.
  • StarSpec: Appended at the end by default. Can be positioned explicitly by adding an entry with section 'StarSpec'.

Entry ID reference

Every ID below can be used as the first element of a sidebar triplet. IDs fall into two categories: tag processors (document types with individual pages) and aggregate processors (cross-cutting summary pages).

Tag processors

Tag processors produce one sidebar entry per document of that type. They support groupByDomain and groupByCategory to create sub-groups.

IDContentSupports
articleJournal articles — free-form writing, research, reflectiongroupByCategory
surfaceUI wireframe sketches (Pug DSL)groupByDomain
tourGuided product tours with narrated stops and spotlightsgroupByDomain
roleUser/system roles
domainDomain models (terms, APIs, policies)
storyUser stories narrating role interactionsgroupByDomain
featureFeature specifications (requirements, criteria, API)groupByDomain
flowStep-by-step interaction flowsgroupByDomain
blueprintImplementation blueprints for developmentgroupByDomain

Aggregate processors

Aggregate processors collect data across all documents and produce summary pages. Most render a single link; some produce expandable sub-items.

IDContentRenders
manifestProduct manifest (values, principles, goals)Single link → /manifest
glossaryAll domain terms sorted alphabeticallySingle link → /glossary
roadmapMilestones and future plansSingle link → /roadmap
tagsAll documents grouped by tagSingle link → /tags
traceabilityRequirement coverage matrix across featuresSingle link → /traceability
api-referenceAll actions, events, operations, errorsExpandable sub-items by API category
policiesBusiness rules: action-event-policy chainsSingle link → /policies
autoflowSystem-wide reactive topology diagramSingle link → /autoflow
settingsConsolidated registry of application settingsSingle link → /settings
surfacesVisual library of all wireframe sketchesSingle link → /surfaces
toursGallery of all product toursSingle link → /tours-gallery
showroomUI component variant galleryExpandable sub-items by category
diagramsInventory of all interactive diagramsSingle link → /diagrams
examplesAll illustrative examples from the specSingle link → /examples
markersWork-in-progress markers across documentsSingle link → /markers
taxonomyHierarchical tag taxonomy treeSingle link → /taxonomy
componentsArchitectural components and wiringExpandable sub-items by domain
article-tagsBrowse articles by tagSingle link → /articles/tags
quotesQuotes collected from articles, grouped by authorSingle link → /quotes
atomsKnowledge atoms (definitions, hypotheses, axioms, etc.)Expandable sub-items by category
bibliographyCited and recommended resources from articlesSingle link → /bibliography

Global transform

The sidebar.transform function is an escape hatch for structural changes that the declarative layer cannot express. It receives the fully assembled SidebarItem[] tree after all entries, changelog, and instructions have been placed, and returns a new tree.

export default defineConfig({
sidebar: {
entries: [ /* ... */ ],
transform: (sidebar) => {
// Reorder sections, inject custom items, strip empty groups, etc.
return sidebar;
},
},
});

The transform runs after SidebarBuilder.build() and before sidebar.json is written. It has full access to the tree shape — sections, groups, links, and badges.


Full example

starspec.config.js
import { defineConfig } from '@starspec/compiler';
export default defineConfig({
sidebar: {
entries: [
// Product
['manifest', 'Product'],
['glossary', 'Product', { label: 'Glossary' }],
['roadmap', 'Product', { label: 'Roadmap' }],
['tour', 'Product/Tours', { collapsed: true, groupByDomain: true }],
['tags', 'Product', { label: 'By Tags' }],
// Journal
['article', 'Journal', { collapsed: false, groupByCategory: true }],
['article-tags', 'Journal', { label: 'By Tag' }],
['quotes', 'Journal', { label: 'Quotes' }],
['atoms', 'Journal', { label: 'Knowledge Base' }],
['bibliography', 'Journal', { label: 'Bibliography' }],
// Specification
['role', 'Specification/Roles', { collapsed: true }],
['domain', 'Specification/Domains', { collapsed: true }],
['story', 'Specification/Stories', { collapsed: true, groupByDomain: true }],
['feature', 'Specification/Features', { collapsed: true, groupByDomain: true }],
['flow', 'Specification/Flows', { collapsed: true, groupByDomain: true }],
['surface', 'Specification/Designs', { collapsed: true, groupByDomain: true }],
// Reference
['traceability', 'Reference', { label: 'Requirements' }],
['api-reference', 'Reference', { label: 'API' }],
['policies', 'Reference/API'],
['autoflow', 'Reference', { label: 'Reactive Topology' }],
['settings', 'Reference', { label: 'Settings' }],
['surfaces', 'Reference', { label: 'Designs' }],
['tours', 'Reference', { label: 'Tours' }],
['showroom', 'Reference', { label: 'Component Gallery' }],
['diagrams', 'Reference', { label: 'Diagrams' }],
['examples', 'Reference', { label: 'Examples' }],
['markers', 'Reference', { label: 'Markers' }],
['taxonomy', 'Reference', { label: 'Taxonomy' }],
// Implementation
['blueprint', 'Implementation/Blueprints', { collapsed: true, groupByDomain: true }],
['components', 'Implementation', { label: 'Components' }],
],
},
});

Adding a new aggregate to the sidebar

After implementing a new AggregateProcessor (see starspec/adding-a-tag § 11), register it in the sidebar by adding a triplet to the entries array in starspec.config.js:

['my-aggregate', 'Reference', { label: 'My Aggregate' }],

The id must match the id property on your AggregateProcessor. If the aggregate produces expandable sub-items via sidebarEntry(), those render automatically — no extra configuration needed. If it only declares a static sidebar property, it renders as a single link.