diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 6da695ee31..8fc1380247 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -73,7 +73,7 @@ The site resolves monorepo packages directly via aliases in `astro.config.mjs`: ## Content collections -Defined in `src/content/config.ts`. Three collections: +Defined in `src/content/config.ts`. Four collections: ### Components (`src/content/components/*.mdx`) @@ -123,12 +123,29 @@ Content here... ``` -**Topics** determine where guidance appears on the component page. Only these values are recognized by the rendering code in `src/lib/content-queries.ts`: +**Topics** determine where guidance appears on the component page. The full set is defined in `src/content/config.ts` and grouped for rendering in `src/lib/content-queries.ts`: -- **Usage tab:** `types`, `states`, `sizing`, `icons`, `positioning`, `content`, `other` -- **Accessibility tab:** `screen-readers`, `keyboard`, `focus` +- **Usage tab:** `types`, `states`, `sizing`, `icons`, `positioning`, `content`, `feedback`, `usage`, `interaction`, `forms`, `layout`, `performance`, `other` +- **Accessibility tab:** `accessibility`, `screen-readers`, `keyboard`, `focus` -The schema in `config.ts` accepts additional topic values (usage, interaction, forms, layout, performance, accessibility, feedback), but any guidance using those topics will be **silently filtered out** and won't render on the page. Stick to the values above. +### Foundations (`src/content/foundations/*.mdx`) + +Design system knowledge documents: principles, anti-patterns, user type guidance. These are reference documents, not atomic items like guidance. + +```yaml +--- +id: principles +title: Design Principles +description: Core design and development principles for teams building with the GoA Design System +category: design # design | development | accessibility +tags: [government-service, accessibility, component-first] +status: published # published | draft | deprecated +--- +``` + +The MDX body contains the actual content as structured markdown (headings, lists, etc.). Currently five files: `principles.mdx`, `anti-patterns.mdx`, `user-types.mdx`, `governance.mdx`, `responsive.mdx`. + +No website pages render this collection yet. It exists for downstream consumers (generators, MCP) and can be wired to pages in the future. ### Examples (`src/content/examples/*/`) diff --git a/docs/src/content/config.ts b/docs/src/content/config.ts index 9e9b241249..ce9ee40f4c 100644 --- a/docs/src/content/config.ts +++ b/docs/src/content/config.ts @@ -157,8 +157,26 @@ const examples = defineCollection({ }), }); +/** + * Foundations Collection + * Design system knowledge documents (principles, anti-patterns, user types) + * These are reference documents, not atomic items like guidance + */ +const foundations = defineCollection({ + type: "content", + schema: z.object({ + id: z.string(), + title: z.string(), + description: z.string(), + category: z.enum(["design", "development", "accessibility"]), + tags: z.array(z.string()).optional(), + status: z.enum(["published", "draft", "deprecated"]).default("published"), + }), +}); + export const collections = { components, guidance, examples, + foundations, }; diff --git a/docs/src/content/foundations/anti-patterns.mdx b/docs/src/content/foundations/anti-patterns.mdx new file mode 100644 index 0000000000..18e52ceffc --- /dev/null +++ b/docs/src/content/foundations/anti-patterns.mdx @@ -0,0 +1,106 @@ +--- +id: anti-patterns +title: Anti-Patterns +description: Common anti-patterns and pitfalls to avoid when using the GoA Design System +category: design +tags: + - anti-patterns + - common-mistakes + - code-quality +status: published +--- + +## Design Anti-Patterns + +### Custom Components Over GoA Components + +**Severity:** High + +Building custom components when equivalent GoA components exist. This fragments the design system, increases maintenance burden, and introduces inconsistencies across government services. + +**Detection:** + +- Custom button, input, or layout components +- Reimplementation of existing patterns + +**Solution:** Exhaust GoA library options before building custom. Check examples for similar patterns. + +--- + +### Mismatched User Type Patterns + +**Severity:** High + +Using citizen patterns for worker tools or vice versa. Citizen and worker services have fundamentally different user needs and interaction models that must not be mixed. + +**Detection:** + +- Worker dashboards with one-question-per-page +- Citizen forms with high information density + +**Solution:** Use appropriate patterns for each user type. See the User Types foundation. + +--- + +### Inconsistent Layout Structure + +**Severity:** Critical + +Not following the right layout pattern for the service type. Citizen-facing services and worker tools have different layout requirements, and mixing patterns breaks visual hierarchy and user expectations. + +**Detection:** + +- Citizen-facing services (like public forms) missing AppHeader or AppFooter +- Worker tools mixing AppHeader/AppFooter with WorkSideMenu +- Inconsistent page structure within the same service + +**Solution:** Use the layout pattern that matches the service type. Citizen services use AppHeader and AppFooter with OneColumnLayout. Worker tools use WorkSideMenu without standard header or footer. + +--- + +### Accessibility as Afterthought + +**Severity:** Critical + +Adding accessibility features after design/development completion. Retrofitting accessibility is far more expensive than building it in from the start, and risks WCAG 2.2 AA non-compliance. + +**Detection:** + +- Form inputs without labels +- Missing ARIA attributes +- Color contrast issues + +**Solution:** Use GoA components which provide accessibility by default. Test early. + +--- + +## Technical Anti-Patterns + +### Custom CSS Over Component Props + +**Severity:** Medium + +Trying to override GoA component appearance with custom CSS. Most attempts won't work anyway because the components use shadow DOM, which isolates styling. The ones that do work create fragile implementations that break on component updates and undermine visual consistency. + +**Detection:** + +- CSS selectors targeting GoA classes or elements +- !important declarations attempting to override component styles +- Wrapper elements with inline styles trying to influence components + +**Solution:** Use component props first. If you genuinely need to customize a component beyond what props allow, GoA components expose component tokens (CSS custom properties) that can be overridden. This is the supported escape hatch and is far better than fighting the shadow DOM. If you find yourself reaching for tokens often, talk to the design system team — there may be a missing prop or a pattern worth adding. + +--- + +### Overuse of GoabSpacer + +**Severity:** Low + +Using GoabSpacer instead of component margin properties. Excessive spacers add unnecessary DOM nodes and ignore built-in spacing controls on components. + +**Detection:** + +- Many GoabSpacer components +- Spacers between components that support margins + +**Solution:** Use component margin props (mb, mt, ml, mr) when available. diff --git a/docs/src/content/foundations/governance.mdx b/docs/src/content/foundations/governance.mdx new file mode 100644 index 0000000000..15cbede297 --- /dev/null +++ b/docs/src/content/foundations/governance.mdx @@ -0,0 +1,78 @@ +--- +id: governance +title: Working with the Design System +description: How teams work with the design system. The happy path for using existing components, requesting changes, and contributing back. +category: design +tags: + - governance + - process + - contribution +status: published +--- + +## The Happy Path + +The design system is a shared resource. Teams work with it through a simple, repeatable process. The goal is to use what exists when it works, talk to the team when it doesn't, and decide together whether something becomes shared or stays a one-off. + +### 1. Use what exists + +Start with the design system. Existing components and patterns cover most service needs. Search the components, look at the examples, and see if you can build what you need with what's already there. + +### 2. Identify the gap + +If you find a real user need that existing components don't handle, that's the signal to talk to the design system team. Real user need means it came from research, testing, or actual service requirements. Not preference, not aesthetic, not "we've always done it this way." + +### 3. Talk to the design system team + +Bring the gap to the team. Don't build around it in isolation. The team can help you understand whether what you need already exists in a form you missed, whether it should be added to the system, or whether your situation is unique enough to be a one-off. + +### 4. Apply the problem-solving hierarchy + +When something doesn't fit, work through these in order before reaching for new components: + +1. **Change the content.** Clearer labels, better instructions, simpler language often solve the problem. +2. **Change the layout.** Rearrange elements, adjust spacing, improve grouping. +3. **Design new components.** Only when content and layout changes don't work. + +Most problems get solved in the first two steps. + +### 5. Test with users + +Validate any new solution with actual users. The design system is evidence-based. Decisions are driven by usability testing and real user needs, not preferences. + +### 6. Share what you learned + +Solutions either get added to the system for everyone, or stay as one-offs for your team. Either way, the design system team needs to know what was tried and what worked so other teams can benefit from the learning. + +## Contribution Criteria + +For something to enter the shared design system, it needs to be: + +- **Useful** — Evidence that the component would be valuable to many teams or services, not just one +- **Unique** — Does not replicate something that already exists in the design system +- **Better** — Creates a better experience, informed by research +- **Universal** — Meets or exceeds WCAG 2.2 AA accessibility standards + +## Roles + +**Design system team:** Guides component selection, reviews compliance, provides expertise, decides what enters the shared system. + +**Product teams:** Define user needs, implement with GoA components, share learnings back. + +Product teams can do what they need to ship their service. The design system team decides what becomes shared across teams. These are two different decisions. + +## Where to find the team + +- **Design System Support channel** on Slack +- **Drop-in Hours** sessions +- **Report a Bug** system for issues +- **Governance board** in FigJam: visual map of the full process and decision points + +## Risk Indicators + +If you notice any of these, it's a signal to pause and talk to the design system team: + +- Building custom components that already exist +- Making changes without user validation +- Working in isolation without design system consultation +- Creating solutions that don't meet accessibility standards diff --git a/docs/src/content/foundations/principles.mdx b/docs/src/content/foundations/principles.mdx new file mode 100644 index 0000000000..21fec1de70 --- /dev/null +++ b/docs/src/content/foundations/principles.mdx @@ -0,0 +1,65 @@ +--- +id: principles +title: Design Principles +description: Core design and development principles for teams building with the GoA Design System +category: design +tags: + - government-service + - accessibility + - component-first + - spacing +status: published +--- + +## Core Principles + +### Government Service First + +All design decisions must prioritize citizen and worker needs over aesthetic preferences. + +**Application:** Choose components and patterns based on user research and government service requirements. + +### Accessibility by Default + +WCAG 2.2 AA compliance is non-negotiable, not an add-on. + +**Application:** Use GoA components which provide built-in accessibility features. + +### Consistency Over Creativity + +Consistent user experience across government services trumps unique design. + +**Application:** Use established GoA patterns rather than inventing new ones. + +### Component-First Thinking + +Exhaust GoA component library options before building custom components. + +**Application:** Search the component library, check examples, combine existing components creatively. + +## Development Principles + +### Component-First Process + +Always start with GoA components until those options are fully exhausted before doing any custom components. + +1. Search for GoA components that solve your need +2. Search with multiple terms (e.g., 'button', 'action', 'submit') +3. Check examples for similar patterns +4. If no component found: Ask the team before building custom + +### Spacing Strategy + +Use component margin props (mb, mr) as the primary spacing approach. + +- Component margin props (mb, mr, mt, ml) - preferred +- GoabBlock for flex layouts +- Custom flexbox/grid when needed +- GoabSpacer for explicit gaps (less responsive) + +### Validation Checklist + +- Verify component properties against documented valid values +- Check design specifications for exact sizing +- Ensure no custom styling - only use component props +- Validate spacing tokens match design system diff --git a/docs/src/content/foundations/responsive.mdx b/docs/src/content/foundations/responsive.mdx new file mode 100644 index 0000000000..664918af5a --- /dev/null +++ b/docs/src/content/foundations/responsive.mdx @@ -0,0 +1,44 @@ +--- +id: responsive +title: Responsive Design +description: Components handle responsive behavior automatically. Trust the defaults, and reach for explicit responsive controls only when you need them. +category: design +tags: + - responsive + - breakpoints + - mobile + - layout +status: published +--- + +## Trust the defaults + +Most GoA components handle responsive behavior internally. A button is full-width on mobile and inline on larger screens. A form item stacks its label on mobile and aligns it inline on desktop. A header collapses to a hamburger menu on small screens. You don't need to write media queries to make these things happen. + +The general rule: build with components, and the responsive behavior comes with them. Reach for explicit responsive control only when you need something the components don't handle on their own. + +## Container queries + +Many components use container queries instead of viewport media queries, which means they respond to the size of their container, not the size of the window. A component placed in a narrow sidebar adapts to that sidebar even on a wide screen. This is mostly invisible — it just works — but it's worth knowing because it changes how you think about responsive layouts. Components don't always look the same at the same viewport width. They look right for the space they're in. + +## Breakpoints + +When you do need to think about screen size explicitly, the design system uses three breakpoints: + +- **Mobile** — under 624px. Phones and small devices. +- **Tablet** — 624px to 1023px. Tablets and medium devices. +- **Desktop** — 1024px and above. Desktop and larger screens. + +These align with how the components themselves adapt, so if you're building custom layouts around GoA components they'll work together at the same breakpoints. + +## Mobile considerations + +Mobile is where responsive matters most. A few patterns to keep in mind: + +- Buttons go full-width by default on mobile, can be overridden +- Form layouts stack labels above inputs +- Navigation collapses +- Block direction switches to column regardless of the direction prop +- Single-column content beats multi-column + +These happen automatically with the components, but if you're laying out a custom screen, follow the same principles. diff --git a/docs/src/content/foundations/user-types.mdx b/docs/src/content/foundations/user-types.mdx new file mode 100644 index 0000000000..72e64efc4c --- /dev/null +++ b/docs/src/content/foundations/user-types.mdx @@ -0,0 +1,152 @@ +--- +id: user-types +title: User Types +description: Two distinct modes shape how government services should be designed. Understanding which mode you're designing for changes everything about the experience. +category: design +tags: + - user-types + - citizen + - service-delivery-worker + - guided + - expert +status: published +--- + +## Citizen vs Service Delivery Worker + +Two distinct modes shape how government services should be designed. Understanding which mode you're designing for changes everything about the experience. + +### Citizen mode + +A citizen is someone accessing a government service from outside government. They might do this once in their life, once a year, or rarely. They didn't choose to be here, they're here because they need something from government. + +**The experience should feel like:** A clear, considered path. Slow on purpose. One step at a time. Plain language. Lots of explanation. Easy to find the next thing. Hard to make a mistake. + +**It values:** Clarity over speed. Confidence over efficiency. Walking someone through something they may never have done before. + +The goal is to simplify while preserving agency. Make the path clear, but don't make decisions for someone that should be theirs to make. Default to choices only when there is one truly right answer. Otherwise, lay out the options and let the person choose. + +Simplification serves understanding. Throwing all the information at someone at once makes it harder to grasp, not easier. Progressive disclosure is the main tool: one thing at a time, in an order that makes sense, surfacing the right information at the right moment. This isn't only about forms. It's a guiding principle for any citizen experience: find the simplest, clearest path through, and curate what someone sees at each step. + +### Service delivery worker mode + +A service delivery worker is someone using a tool to deliver or administer a government service from inside government. They use it every day. It is their job. They know what they are doing. + +**The experience should feel like:** A power tool. Fast. Dense. Information-rich. Predictable. Constant feedback so you always know what just happened. Built for repetition and scale. + +**It values:** Efficiency over guidance. Density over whitespace. Trusting expertise. Letting the person move through their work without the system slowing them down with explanations they have already internalized. + +It is not stripped down. It is loaded with everything an expert needs, organized so the right thing is always at hand. + +### The key insight + +Frequency matters more than identity. A contractor filing daily permits is technically a citizen, but they need service delivery worker patterns. A service delivery worker handling a once-in-a-career regulatory exception needs guided patterns. The mode is about the relationship to the task, not the person's role. + +## Classification Framework + +Two dimensions help identify which mode applies: who the person is in relation to the service, and how often they use it. + +### Dimension 1: Role + +**Receiving Service** — People accessing or benefiting from government services + +- Citizens +- Businesses +- Professional intermediaries (lawyers, contractors) + +**Giving Service** — People administering or managing government services + +- Government service delivery workers +- Service providers +- Staff processing applications + +### Dimension 2: Frequency + +**Guided / Infrequent** + +- Frequency: Once in a lifetime, annually, or rare +- Mental model: "Help me through this process" +- Needs: Step-by-step guidance, clear explanations, error prevention, save progress + +**Expert / Frequent** + +- Frequency: Daily, weekly, or routine +- Mental model: "I know what I'm doing, make me efficient" +- Needs: Shortcuts, bulk actions, dense information, speed + +## Design Patterns + +### Citizen mode (guided) + +**Approach:** + +- Progressive disclosure — break into manageable steps +- Plain language at grade 9 reading level +- Error prevention with validation and confirmations +- Inline help and examples +- Allow saving progress across sessions + +**Recommended components:** + +- GoabFormItem with help text +- GoabCallout for guidance +- GoabDetails for disclosure +- Clear progress indicators + +**Layouts:** + +- Single question per page +- Prominent help +- Large obvious action buttons +- AppHeader and AppFooter with OneColumnLayout + +### Service delivery worker mode (expert) + +**Approach:** + +- Dense information display +- Keyboard shortcuts and quick actions +- Bulk operations for efficiency +- Advanced filtering and sorting +- Customizable interfaces +- Constant feedback so users know what just happened + +**Recommended components:** + +- GoabTable with sorting +- GoabButtonGroup for bulk actions +- GoabTabs for density +- GoabPagination + +**Layouts:** + +- Information-dense layouts +- Multiple actions per screen +- Advanced filtering +- WorkSideMenu without standard header or footer + +## Examples + +### Citizen mode + Guided + +**Scenario:** Citizen buying first home + +**Pattern:** Step-by-step wizard, extensive help, one question per page + +### Citizen mode + Expert + +**Scenario:** Contractor filing routine permits + +**Pattern:** Efficient form, bulk submission, saved preferences. Even though the user is a citizen, frequency makes service delivery worker patterns the right choice. + +### Service delivery worker mode + Guided + +**Scenario:** Service delivery worker handling complex regulatory exception + +**Pattern:** Procedural guidance, compliance checklists, validation. Even though the user is a service delivery worker, the rare and high-stakes nature makes guided patterns the right choice. + +### Service delivery worker mode + Expert + +**Scenario:** Case worker processing daily applications + +**Pattern:** Dashboard with queues, bulk actions, keyboard shortcuts diff --git a/docs/src/content/guidance/badge-arialabel-icon-only.mdx b/docs/src/content/guidance/badge-arialabel-icon-only.mdx new file mode 100644 index 0000000000..c9e38f3214 --- /dev/null +++ b/docs/src/content/guidance/badge-arialabel-icon-only.mdx @@ -0,0 +1,17 @@ +--- +id: badge-arialabel-icon-only +type: warning +description: When using an icon-only badge, ariaLabel is required so screen readers can identify it. +topic: screen-readers +tags: + - badge + - accessibility + - icons +appliesTo: + components: + - badge +relatedProps: + - ariaLabel + - icon +status: published +--- diff --git a/docs/src/content/guidance/block-vs-buttongroup.mdx b/docs/src/content/guidance/block-vs-buttongroup.mdx new file mode 100644 index 0000000000..fe5055152e --- /dev/null +++ b/docs/src/content/guidance/block-vs-buttongroup.mdx @@ -0,0 +1,15 @@ +--- +id: block-vs-buttongroup +type: tip +description: Use Block for general layout and spacing. Use ButtonGroup for semantically related action buttons. +topic: other +tags: + - block + - button-group + - layout +appliesTo: + components: + - block + - button-group +status: published +--- diff --git a/docs/src/content/guidance/buttongroup-end-alignment-modal.mdx b/docs/src/content/guidance/buttongroup-end-alignment-modal.mdx new file mode 100644 index 0000000000..94393a16c1 --- /dev/null +++ b/docs/src/content/guidance/buttongroup-end-alignment-modal.mdx @@ -0,0 +1,16 @@ +--- +id: buttongroup-end-alignment-modal +type: tip +description: Use 'end' alignment for modal action buttons so they sit at the bottom right, following the natural reading flow. +topic: positioning +tags: + - button-group + - modal + - alignment +appliesTo: + components: + - button-group +relatedProps: + - alignment +status: published +--- diff --git a/docs/src/content/guidance/buttongroup-gap-matches-button-size.mdx b/docs/src/content/guidance/buttongroup-gap-matches-button-size.mdx new file mode 100644 index 0000000000..6431a5a4b3 --- /dev/null +++ b/docs/src/content/guidance/buttongroup-gap-matches-button-size.mdx @@ -0,0 +1,15 @@ +--- +id: buttongroup-gap-matches-button-size +type: tip +description: Match gap to button size. Use 'relaxed' gap with normal-sized buttons and 'compact' gap with compact buttons. +topic: sizing +tags: + - button-group + - spacing +appliesTo: + components: + - button-group +relatedProps: + - gap +status: published +--- diff --git a/docs/src/content/guidance/callout-arialive-polite-vs-assertive.mdx b/docs/src/content/guidance/callout-arialive-polite-vs-assertive.mdx new file mode 100644 index 0000000000..c00485dc3e --- /dev/null +++ b/docs/src/content/guidance/callout-arialive-polite-vs-assertive.mdx @@ -0,0 +1,15 @@ +--- +id: callout-arialive-polite-vs-assertive +type: tip +description: Use ariaLive='polite' for status updates. Use 'assertive' for urgent messages that should interrupt the user immediately. +topic: screen-readers +tags: + - callout + - accessibility +appliesTo: + components: + - callout +relatedProps: + - ariaLive +status: published +--- diff --git a/docs/src/content/guidance/checkbox-description-for-context.mdx b/docs/src/content/guidance/checkbox-description-for-context.mdx new file mode 100644 index 0000000000..e32c307342 --- /dev/null +++ b/docs/src/content/guidance/checkbox-description-for-context.mdx @@ -0,0 +1,16 @@ +--- +id: checkbox-description-for-context +type: tip +description: Use the description prop to add context on complex options where the label alone isn't enough. +topic: content +tags: + - checkbox + - labels +appliesTo: + components: + - checkbox + - checkbox-list +relatedProps: + - description +status: published +--- diff --git a/docs/src/content/guidance/circular-progress-dont-fullscreen-quick.mdx b/docs/src/content/guidance/circular-progress-dont-fullscreen-quick.mdx new file mode 100644 index 0000000000..cb72ce8bd3 --- /dev/null +++ b/docs/src/content/guidance/circular-progress-dont-fullscreen-quick.mdx @@ -0,0 +1,16 @@ +--- +id: circular-progress-dont-fullscreen-quick +type: dont +description: Don't use the fullscreen variant for quick operations. For anything under a second, use inline or Spinner. When part of a page is loading but the rest can show, use Skeleton to load progressively instead of blocking the whole view. +topic: types +tags: + - circular-progress + - loading + - performance +appliesTo: + components: + - circular-progress +relatedProps: + - variant +status: published +--- diff --git a/docs/src/content/guidance/circular-progress-hidden-by-default.mdx b/docs/src/content/guidance/circular-progress-hidden-by-default.mdx new file mode 100644 index 0000000000..7ab238b083 --- /dev/null +++ b/docs/src/content/guidance/circular-progress-hidden-by-default.mdx @@ -0,0 +1,15 @@ +--- +id: circular-progress-hidden-by-default +type: warning +description: CircularProgress is hidden by default. Always set visible={true} to show it. +topic: states +tags: + - circular-progress + - loading +appliesTo: + components: + - circular-progress +relatedProps: + - visible +status: published +--- diff --git a/docs/src/content/guidance/circular-progress-message-prop.mdx b/docs/src/content/guidance/circular-progress-message-prop.mdx new file mode 100644 index 0000000000..65a4f6c68c --- /dev/null +++ b/docs/src/content/guidance/circular-progress-message-prop.mdx @@ -0,0 +1,15 @@ +--- +id: circular-progress-message-prop +type: tip +description: Provide a message prop to explain what operation is in progress, like "Loading your application" or "Saving changes." +topic: content +tags: + - circular-progress + - loading +appliesTo: + components: + - circular-progress +relatedProps: + - message +status: published +--- diff --git a/docs/src/content/guidance/container-accent-thick-for-header.mdx b/docs/src/content/guidance/container-accent-thick-for-header.mdx new file mode 100644 index 0000000000..f3638e451f --- /dev/null +++ b/docs/src/content/guidance/container-accent-thick-for-header.mdx @@ -0,0 +1,15 @@ +--- +id: container-accent-thick-for-header +type: tip +description: Use accent='thick' when you need a header area with a title or actions on a container. +topic: types +tags: + - container + - header +appliesTo: + components: + - container +relatedProps: + - accent +status: published +--- diff --git a/docs/src/content/guidance/datepicker-set-min-max.mdx b/docs/src/content/guidance/datepicker-set-min-max.mdx new file mode 100644 index 0000000000..699e3e8fd5 --- /dev/null +++ b/docs/src/content/guidance/datepicker-set-min-max.mdx @@ -0,0 +1,17 @@ +--- +id: datepicker-set-min-max +type: tip +description: Set appropriate min and max dates for your use case. A birthdate field should limit to past dates, a booking field to future dates. +topic: states +tags: + - date-picker + - validation + - forms +appliesTo: + components: + - date-picker +relatedProps: + - min + - max +status: published +--- diff --git a/docs/src/content/guidance/dont-use-stepper-for-nonsequential.mdx b/docs/src/content/guidance/dont-use-stepper-for-nonsequential.mdx new file mode 100644 index 0000000000..fae9cce179 --- /dev/null +++ b/docs/src/content/guidance/dont-use-stepper-for-nonsequential.mdx @@ -0,0 +1,13 @@ +--- +id: dont-use-stepper-for-nonsequential +type: dont +description: Don't use FormStepper for non-sequential navigation. +topic: other +tags: + - form-stepper + - navigation +appliesTo: + components: + - form-stepper +status: published +--- diff --git a/docs/src/content/guidance/drawer-position-right-vs-bottom.mdx b/docs/src/content/guidance/drawer-position-right-vs-bottom.mdx new file mode 100644 index 0000000000..eab71e5458 --- /dev/null +++ b/docs/src/content/guidance/drawer-position-right-vs-bottom.mdx @@ -0,0 +1,16 @@ +--- +id: drawer-position-right-vs-bottom +type: tip +description: Use position='right' for forms and detail panels. Use position='bottom' for mobile-friendly bottom sheets. +topic: types +tags: + - drawer + - layout + - responsive +appliesTo: + components: + - drawer +relatedProps: + - position +status: published +--- diff --git a/docs/src/content/guidance/dropdown-arialabel-without-formitem.mdx b/docs/src/content/guidance/dropdown-arialabel-without-formitem.mdx new file mode 100644 index 0000000000..6891fefc3b --- /dev/null +++ b/docs/src/content/guidance/dropdown-arialabel-without-formitem.mdx @@ -0,0 +1,16 @@ +--- +id: dropdown-arialabel-without-formitem +type: warning +description: When a Dropdown is not wrapped in a FormItem, set ariaLabel to provide an accessible name. Without it, screen readers won't be able to identify the dropdown. +topic: screen-readers +tags: + - dropdown + - accessibility + - forms +appliesTo: + components: + - dropdown +relatedProps: + - ariaLabel +status: published +--- diff --git a/docs/src/content/guidance/fileuploader-helper-text.mdx b/docs/src/content/guidance/fileuploader-helper-text.mdx index b20501cd28..92975b511e 100644 --- a/docs/src/content/guidance/fileuploader-helper-text.mdx +++ b/docs/src/content/guidance/fileuploader-helper-text.mdx @@ -9,7 +9,7 @@ tags: - forms appliesTo: components: - - file-uploader + - file-upload-input status: published --- diff --git a/docs/src/content/guidance/fileuploader-show-max-size.mdx b/docs/src/content/guidance/fileuploader-show-max-size.mdx index 1877101e1a..a6abb3f0b5 100644 --- a/docs/src/content/guidance/fileuploader-show-max-size.mdx +++ b/docs/src/content/guidance/fileuploader-show-max-size.mdx @@ -8,7 +8,7 @@ tags: - usability appliesTo: components: - - file-uploader + - file-upload-input status: published --- diff --git a/docs/src/content/guidance/filterchip-vs-badge.mdx b/docs/src/content/guidance/filterchip-vs-badge.mdx new file mode 100644 index 0000000000..94876bc3c2 --- /dev/null +++ b/docs/src/content/guidance/filterchip-vs-badge.mdx @@ -0,0 +1,14 @@ +--- +id: filterchip-vs-badge +type: tip +description: FilterChip is for removable filters that users can dismiss. For static labels or status indicators, use Badge instead. +topic: types +tags: + - filter-chip + - badge +appliesTo: + components: + - filter-chip + - badge +status: published +--- diff --git a/docs/src/content/guidance/formitem-label-size-large.mdx b/docs/src/content/guidance/formitem-label-size-large.mdx new file mode 100644 index 0000000000..d5e30e87f1 --- /dev/null +++ b/docs/src/content/guidance/formitem-label-size-large.mdx @@ -0,0 +1,16 @@ +--- +id: formitem-label-size-large +type: tip +description: Use labelSize='large' when you want the question to act as the heading on the page. This is often the right choice when there's only one question on a page, so you don't end up with a separate heading and a question saying the same thing. +topic: sizing +tags: + - form-item + - forms + - labels +appliesTo: + components: + - form-item +relatedProps: + - labelSize +status: published +--- diff --git a/docs/src/content/guidance/grid-minchildwidth-required.mdx b/docs/src/content/guidance/grid-minchildwidth-required.mdx new file mode 100644 index 0000000000..312275d81c --- /dev/null +++ b/docs/src/content/guidance/grid-minchildwidth-required.mdx @@ -0,0 +1,16 @@ +--- +id: grid-minchildwidth-required +type: warning +description: minChildWidth is required on Grid. Set it based on the content's minimum readable width so items wrap properly. +topic: sizing +tags: + - grid + - responsive + - layout +appliesTo: + components: + - grid +relatedProps: + - minChildWidth +status: published +--- diff --git a/docs/src/content/guidance/header-consistent-maxcontentwidth.mdx b/docs/src/content/guidance/header-consistent-maxcontentwidth.mdx new file mode 100644 index 0000000000..d26a86d55d --- /dev/null +++ b/docs/src/content/guidance/header-consistent-maxcontentwidth.mdx @@ -0,0 +1,15 @@ +--- +id: header-consistent-maxcontentwidth +type: tip +description: Use consistent maxContentWidth with your page layout so the header aligns with the content below it. +topic: positioning +tags: + - app-header + - layout +appliesTo: + components: + - app-header +relatedProps: + - maxContentWidth +status: published +--- diff --git a/docs/src/content/guidance/header-heading-identifies-service.mdx b/docs/src/content/guidance/header-heading-identifies-service.mdx new file mode 100644 index 0000000000..a1d5823b67 --- /dev/null +++ b/docs/src/content/guidance/header-heading-identifies-service.mdx @@ -0,0 +1,15 @@ +--- +id: header-heading-identifies-service +type: warning +description: Always provide a heading prop on AppHeader to identify your service. Without it, users won't know which service they're using. +topic: content +tags: + - app-header + - government +appliesTo: + components: + - app-header +relatedProps: + - heading +status: published +--- diff --git a/docs/src/content/guidance/linear-progress-hide-percent-indeterminate.mdx b/docs/src/content/guidance/linear-progress-hide-percent-indeterminate.mdx new file mode 100644 index 0000000000..3e15cf36a5 --- /dev/null +++ b/docs/src/content/guidance/linear-progress-hide-percent-indeterminate.mdx @@ -0,0 +1,15 @@ +--- +id: linear-progress-hide-percent-indeterminate +type: dont +description: Don't show a percentage for indeterminate progress. Showing '0%' when there's no known progress is confusing. +topic: states +tags: + - linear-progress + - loading +appliesTo: + components: + - linear-progress +relatedProps: + - percentVisibility +status: published +--- diff --git a/docs/src/content/guidance/link-trailing-icon-external.mdx b/docs/src/content/guidance/link-trailing-icon-external.mdx new file mode 100644 index 0000000000..b325247f6a --- /dev/null +++ b/docs/src/content/guidance/link-trailing-icon-external.mdx @@ -0,0 +1,16 @@ +--- +id: link-trailing-icon-external +type: tip +description: Use trailingIcon='open' for links that go to external sites so users know they're leaving the service. +topic: icons +tags: + - link + - external + - icons +appliesTo: + components: + - link +relatedProps: + - trailingIcon +status: published +--- diff --git a/docs/src/content/guidance/link-vs-button.mdx b/docs/src/content/guidance/link-vs-button.mdx new file mode 100644 index 0000000000..9cab928bd8 --- /dev/null +++ b/docs/src/content/guidance/link-vs-button.mdx @@ -0,0 +1,15 @@ +--- +id: link-vs-button +type: tip +description: Use Link for navigation to other pages. Use Button for actions that change state or trigger functionality. +topic: other +tags: + - link + - button + - navigation +appliesTo: + components: + - link + - button +status: published +--- diff --git a/docs/src/content/guidance/menubutton-not-for-navigation.mdx b/docs/src/content/guidance/menubutton-not-for-navigation.mdx new file mode 100644 index 0000000000..e4194bc874 --- /dev/null +++ b/docs/src/content/guidance/menubutton-not-for-navigation.mdx @@ -0,0 +1,13 @@ +--- +id: menubutton-not-for-navigation +type: dont +description: Don't use MenuButton for navigation menus. Use AppHeaderMenu or SideMenu for navigation. MenuButton is for action lists. +topic: other +tags: + - menu-button + - navigation +appliesTo: + components: + - menu-button +status: published +--- diff --git a/docs/src/content/guidance/modal-closable-false-for-critical.mdx b/docs/src/content/guidance/modal-closable-false-for-critical.mdx new file mode 100644 index 0000000000..286996bebe --- /dev/null +++ b/docs/src/content/guidance/modal-closable-false-for-critical.mdx @@ -0,0 +1,15 @@ +--- +id: modal-closable-false-for-critical +type: tip +description: Use closable=false for critical confirmations where the user must choose an explicit action, not just dismiss the dialog. +topic: other +tags: + - modal + - confirmation +appliesTo: + components: + - modal +relatedProps: + - closable +status: published +--- diff --git a/docs/src/content/guidance/notification-vs-temporary.mdx b/docs/src/content/guidance/notification-vs-temporary.mdx new file mode 100644 index 0000000000..e3df9db9a8 --- /dev/null +++ b/docs/src/content/guidance/notification-vs-temporary.mdx @@ -0,0 +1,15 @@ +--- +id: notification-vs-temporary +type: tip +description: For temporary toast-style messages, use TemporaryNotification instead of Notification. Notification stays on screen until dismissed. +topic: types +tags: + - notification + - temporary-notification + - feedback +appliesTo: + components: + - notification + - temporary-notification +status: published +--- diff --git a/docs/src/content/guidance/pagination-links-only-mobile.mdx b/docs/src/content/guidance/pagination-links-only-mobile.mdx new file mode 100644 index 0000000000..32f03077bd --- /dev/null +++ b/docs/src/content/guidance/pagination-links-only-mobile.mdx @@ -0,0 +1,16 @@ +--- +id: pagination-links-only-mobile +type: tip +description: Use variant='links-only' for a simpler mobile-friendly pagination with just previous and next buttons. +topic: types +tags: + - pagination + - responsive + - mobile +appliesTo: + components: + - pagination +relatedProps: + - variant +status: published +--- diff --git a/docs/src/content/guidance/picking-a-date-component.mdx b/docs/src/content/guidance/picking-a-date-component.mdx new file mode 100644 index 0000000000..394817b37d --- /dev/null +++ b/docs/src/content/guidance/picking-a-date-component.mdx @@ -0,0 +1,15 @@ +--- +id: picking-a-date-component +type: tip +description: "DatePicker handles most date inputs. Use type='input' (a dropdown for month and text inputs for day and year) for known dates like birthdays, far in the past or far in the future. Use type='calendar' (a popup calendar) for dates closer to the current day when the user is picking from available days, like booking or scheduling." +topic: types +tags: + - date-picker + - forms +appliesTo: + components: + - date-picker +relatedProps: + - type +status: published +--- diff --git a/docs/src/content/guidance/picking-a-loading-indicator.mdx b/docs/src/content/guidance/picking-a-loading-indicator.mdx new file mode 100644 index 0000000000..9f626f0981 --- /dev/null +++ b/docs/src/content/guidance/picking-a-loading-indicator.mdx @@ -0,0 +1,17 @@ +--- +id: picking-a-loading-indicator +type: tip +description: "Pick the loading indicator that matches the context. Use CircularProgress with the inline variant for a section of the page that's loading. Use the fullscreen variant when the whole page is loading and the user can't do anything else yet. Use Skeleton when part of the page can show while the rest loads, so users see structure right away instead of an empty space." +topic: types +tags: + - circular-progress + - skeleton + - loading +appliesTo: + components: + - circular-progress + - skeleton +relatedProps: + - variant +status: published +--- diff --git a/docs/src/content/guidance/radio-description-for-context.mdx b/docs/src/content/guidance/radio-description-for-context.mdx new file mode 100644 index 0000000000..d9f16971a8 --- /dev/null +++ b/docs/src/content/guidance/radio-description-for-context.mdx @@ -0,0 +1,17 @@ +--- +id: radio-description-for-context +type: tip +description: Use the description prop to add context on radio options where the label alone isn't enough to explain the choice. +topic: content +tags: + - radio + - labels + - forms +appliesTo: + components: + - radio-item + - radio-group +relatedProps: + - description +status: published +--- diff --git a/docs/src/content/guidance/radio-dont-more-than-seven.mdx b/docs/src/content/guidance/radio-dont-more-than-seven.mdx index 1bf8c79dcd..3c185a0abc 100644 --- a/docs/src/content/guidance/radio-dont-more-than-seven.mdx +++ b/docs/src/content/guidance/radio-dont-more-than-seven.mdx @@ -8,7 +8,7 @@ tags: - dropdown appliesTo: components: - - radio + - radio-group status: published --- diff --git a/docs/src/content/guidance/radio-dont-nest-revealed-content.mdx b/docs/src/content/guidance/radio-dont-nest-revealed-content.mdx index 619892161e..6b108493a7 100644 --- a/docs/src/content/guidance/radio-dont-nest-revealed-content.mdx +++ b/docs/src/content/guidance/radio-dont-nest-revealed-content.mdx @@ -9,7 +9,7 @@ tags: - accessibility appliesTo: components: - - radio + - radio-group status: published --- @@ -17,7 +17,7 @@ status: published - + diff --git a/docs/src/content/guidance/radio-dont-period-after-label.mdx b/docs/src/content/guidance/radio-dont-period-after-label.mdx index ff8f0ab54a..88ade4598d 100644 --- a/docs/src/content/guidance/radio-dont-period-after-label.mdx +++ b/docs/src/content/guidance/radio-dont-period-after-label.mdx @@ -8,7 +8,7 @@ tags: - labels appliesTo: components: - - radio + - radio-group status: published --- diff --git a/docs/src/content/guidance/radio-dont-preselect.mdx b/docs/src/content/guidance/radio-dont-preselect.mdx index 76156b23f5..6c180c9399 100644 --- a/docs/src/content/guidance/radio-dont-preselect.mdx +++ b/docs/src/content/guidance/radio-dont-preselect.mdx @@ -8,7 +8,7 @@ tags: - defaults appliesTo: components: - - radio + - radio-group status: published --- diff --git a/docs/src/content/guidance/radio-horizontal-short-options.mdx b/docs/src/content/guidance/radio-horizontal-short-options.mdx index a92f5058b4..0919b5b009 100644 --- a/docs/src/content/guidance/radio-horizontal-short-options.mdx +++ b/docs/src/content/guidance/radio-horizontal-short-options.mdx @@ -8,7 +8,7 @@ tags: - layout appliesTo: components: - - radio + - radio-group status: published --- diff --git a/docs/src/content/guidance/radioitem-reveal-aria-label.mdx b/docs/src/content/guidance/radioitem-reveal-aria-label.mdx new file mode 100644 index 0000000000..990df02b37 --- /dev/null +++ b/docs/src/content/guidance/radioitem-reveal-aria-label.mdx @@ -0,0 +1,17 @@ +--- +id: radioitem-reveal-aria-label +type: warning +description: When using the reveal slot, set revealAriaLabel so screen readers announce the newly visible content. +topic: screen-readers +tags: + - radio + - accessibility + - forms +appliesTo: + components: + - radio-item + - radio-group +relatedProps: + - revealAriaLabel +status: published +--- diff --git a/docs/src/content/guidance/radioitem-reveal-slot.mdx b/docs/src/content/guidance/radioitem-reveal-slot.mdx new file mode 100644 index 0000000000..ee9c429986 --- /dev/null +++ b/docs/src/content/guidance/radioitem-reveal-slot.mdx @@ -0,0 +1,15 @@ +--- +id: radioitem-reveal-slot +type: tip +description: Use the reveal slot to show additional content when a radio option is selected, like a follow-up question or input field. +topic: other +tags: + - radio + - forms + - conditional-content +appliesTo: + components: + - radio-item + - radio-group +status: published +--- diff --git a/docs/src/content/guidance/skeleton-error-state-timeout.mdx b/docs/src/content/guidance/skeleton-error-state-timeout.mdx new file mode 100644 index 0000000000..c5b92db752 --- /dev/null +++ b/docs/src/content/guidance/skeleton-error-state-timeout.mdx @@ -0,0 +1,14 @@ +--- +id: skeleton-error-state-timeout +type: warning +description: Show an error state if loading takes too long. Don't leave skeletons showing indefinitely without feedback. +topic: states +tags: + - skeleton + - loading + - error-handling +appliesTo: + components: + - skeleton +status: published +--- diff --git a/docs/src/content/guidance/skeleton-match-content-shape.mdx b/docs/src/content/guidance/skeleton-match-content-shape.mdx new file mode 100644 index 0000000000..40712accf2 --- /dev/null +++ b/docs/src/content/guidance/skeleton-match-content-shape.mdx @@ -0,0 +1,15 @@ +--- +id: skeleton-match-content-shape +type: tip +description: Match the skeleton type to your actual content shape. Accurate shapes reduce perceived load time and prevent layout shifts. +topic: types +tags: + - skeleton + - loading +appliesTo: + components: + - skeleton +relatedProps: + - type +status: published +--- diff --git a/docs/src/content/guidance/table-relaxed-for-long-content.mdx b/docs/src/content/guidance/table-relaxed-for-long-content.mdx new file mode 100644 index 0000000000..015a07b1ee --- /dev/null +++ b/docs/src/content/guidance/table-relaxed-for-long-content.mdx @@ -0,0 +1,15 @@ +--- +id: table-relaxed-for-long-content +type: tip +description: Use variant='relaxed' for tables with longer content that needs more breathing room between rows. +topic: types +tags: + - table + - content +appliesTo: + components: + - table +relatedProps: + - variant +status: published +--- diff --git a/docs/src/content/guidance/temporary-notification-not-for-errors.mdx b/docs/src/content/guidance/temporary-notification-not-for-errors.mdx new file mode 100644 index 0000000000..49b0c14293 --- /dev/null +++ b/docs/src/content/guidance/temporary-notification-not-for-errors.mdx @@ -0,0 +1,15 @@ +--- +id: temporary-notification-not-for-errors +type: dont +description: Don't show critical errors that require user action in a temporary notification. They auto-dismiss and can be missed. Use Callout or Notification instead. +topic: types +tags: + - temporary-notification + - callout + - notification + - error-handling +appliesTo: + components: + - temporary-notification +status: published +--- diff --git a/docs/src/content/guidance/text-secondary-color.mdx b/docs/src/content/guidance/text-secondary-color.mdx new file mode 100644 index 0000000000..c23f5e79c5 --- /dev/null +++ b/docs/src/content/guidance/text-secondary-color.mdx @@ -0,0 +1,16 @@ +--- +id: text-secondary-color +type: tip +description: Use color='secondary' for supporting text that's less prominent than the main content. +topic: types +tags: + - text + - color + - typography +appliesTo: + components: + - text +relatedProps: + - color +status: published +--- diff --git a/docs/src/content/guidance/text-semantic-heading-tags.mdx b/docs/src/content/guidance/text-semantic-heading-tags.mdx new file mode 100644 index 0000000000..d35018f514 --- /dev/null +++ b/docs/src/content/guidance/text-semantic-heading-tags.mdx @@ -0,0 +1,16 @@ +--- +id: text-semantic-heading-tags +type: warning +description: Use semantic heading tags (h1-h5) with GoabText for proper document structure and screen reader navigation. +topic: screen-readers +tags: + - text + - accessibility + - headings +appliesTo: + components: + - text +relatedProps: + - tag +status: published +--- diff --git a/docs/src/content/guidance/textarea-countby-word-vs-character.mdx b/docs/src/content/guidance/textarea-countby-word-vs-character.mdx new file mode 100644 index 0000000000..687ece39ff --- /dev/null +++ b/docs/src/content/guidance/textarea-countby-word-vs-character.mdx @@ -0,0 +1,16 @@ +--- +id: textarea-countby-word-vs-character +type: tip +description: Use countBy='word' when suggesting a response length. Use countBy='character' when enforcing a hard limit. +topic: content +tags: + - text-area + - forms + - validation +appliesTo: + components: + - text-area +relatedProps: + - countBy +status: published +--- diff --git a/docs/src/content/guidance/use-radiogroup-with-radioitem.mdx b/docs/src/content/guidance/use-radiogroup-with-radioitem.mdx new file mode 100644 index 0000000000..7221163c56 --- /dev/null +++ b/docs/src/content/guidance/use-radiogroup-with-radioitem.mdx @@ -0,0 +1,14 @@ +--- +id: use-radiogroup-with-radioitem +type: tip +description: Always use RadioGroup as the parent for sets of RadioItem children. Don't try to build radio button sets manually. +topic: other +tags: + - radio + - forms +appliesTo: + components: + - radio-group + - radio-item +status: published +--- diff --git a/docs/src/content/guidance/validate-files-before-upload.mdx b/docs/src/content/guidance/validate-files-before-upload.mdx new file mode 100644 index 0000000000..8e62f82ef8 --- /dev/null +++ b/docs/src/content/guidance/validate-files-before-upload.mdx @@ -0,0 +1,14 @@ +--- +id: validate-files-before-upload +type: tip +description: "Validate as much as possible before the upload starts. File type, size, and other client-side checks should happen first so the file doesn't begin uploading until it's known to be valid. Once an upload is in progress, the only error a user should see on the file upload card is something like a network or server problem." +topic: other +tags: + - file-upload + - validation +appliesTo: + components: + - file-upload-input + - file-upload-card +status: published +--- diff --git a/docs/src/content/guidance/worksidemenu-for-worker-mode.mdx b/docs/src/content/guidance/worksidemenu-for-worker-mode.mdx new file mode 100644 index 0000000000..6560b80d75 --- /dev/null +++ b/docs/src/content/guidance/worksidemenu-for-worker-mode.mdx @@ -0,0 +1,12 @@ +--- +id: worksidemenu-for-worker-mode +type: tip +description: "Use WorkSideMenu when the experience is in worker mode: a productive, power-user tool where users move through dense work efficiently. This isn't only about government staff. Some citizen-facing services are also worker mode, like a contractor who files permits daily. Don't use WorkSideMenu in simplified, guided experiences like public forms." +topic: other +tags: + - work-side-menu +appliesTo: + components: + - work-side-menu +status: published +--- diff --git a/docs/src/content/guidance/wrap-content-in-pageblock.mdx b/docs/src/content/guidance/wrap-content-in-pageblock.mdx new file mode 100644 index 0000000000..5007f1b679 --- /dev/null +++ b/docs/src/content/guidance/wrap-content-in-pageblock.mdx @@ -0,0 +1,15 @@ +--- +id: wrap-content-in-pageblock +type: tip +description: GoabPageBlock with a width prop is one way to constrain main content within OneColumnLayout. It gives you a quick, consistent content width without having to handle that yourself. +topic: other +tags: + - page-block + - layout +appliesTo: + components: + - page-block +relatedProps: + - width +status: published +--- diff --git a/docs/src/lib/content-queries.ts b/docs/src/lib/content-queries.ts index 427be4f797..2be5abcf8e 100644 --- a/docs/src/lib/content-queries.ts +++ b/docs/src/lib/content-queries.ts @@ -119,9 +119,20 @@ export const USAGE_TOPICS = [ "icons", "positioning", "content", + "feedback", + "usage", + "interaction", + "forms", + "layout", + "performance", "other", ] as const; -export const ACCESSIBILITY_TOPICS = ["screen-readers", "keyboard", "focus"] as const; +export const ACCESSIBILITY_TOPICS = [ + "accessibility", + "screen-readers", + "keyboard", + "focus", +] as const; /** * Separate guidance into usage and accessibility categories