-
+
2152 Icon Custom Alignment
@@ -53,7 +59,9 @@ export function App() {
3118 Text Component ID
3201 Input Component Events
3215 Drawer Initial Height
+ 3232 GoabText Tag Size
3248 Dropdown Dynamic Children Sync
+ 3275 Can't unset month
3322 App Header Menu Hover
@@ -76,10 +84,13 @@ export function App() {
2829 Modal ARIA Live Region
2877 Badge Types and Custom Icon
3102 MenuButton Width
+ 3241 V2 Experimental Wrappers
+ v2 header icons
+ 3137 Work Side Menu Group
+ 3306 Custom slug value for tabs
A
- B
diff --git a/apps/prs/react/src/main.tsx b/apps/prs/react/src/main.tsx
index 4ab4406e3c..8c70bfc64a 100644
--- a/apps/prs/react/src/main.tsx
+++ b/apps/prs/react/src/main.tsx
@@ -37,7 +37,9 @@ import { Bug2977Route } from "./routes/bugs/bug2977";
import { Bug3118Route } from "./routes/bugs/bug3118";
import { Bug3201Route } from "./routes/bugs/bug3201";
import { Bug3215Route } from "./routes/bugs/bug3215";
+import { Bug3232Route } from "./routes/bugs/bug3232";
import { Bug3248Route } from "./routes/bugs/bug3248";
+import { Bug3275Route } from "./routes/bugs/bug3275";
import { Bug3322Route } from "./routes/bugs/bug3322";
import { EverythingRoute } from "./routes/everything";
@@ -53,14 +55,18 @@ import { Feat2267Route } from "./routes/features/feat2267";
import { Feat2440Route } from "./routes/features/feat2440";
import { Feat2492Route } from "./routes/features/feat2492";
import { Feat2609Route } from "./routes/features/feat2609";
+import { Feat2611Route } from "./routes/features/feat2611";
import Feat2611TabsDisabledRoute from "./routes/features/feat2611-tabs-disabled";
import { Feat2682Route } from "./routes/features/feat2682";
import { Feat2722Route } from "./routes/features/feat2722";
import { Feat2730Route } from "./routes/features/feat2730";
import { Feat2829Route } from "./routes/features/feat2829";
import { Feat2877Route } from "./routes/features/feat2877";
-import Feat3102Route from "./routes/features/feat3102";
-import { Feat2611Route } from "./routes/features/feat2611";
+import { Feat3102Route } from "./routes/features/feat3102";
+import { Feat3241Route } from "./routes/features/feat3241";
+import { FeatV2IconsRoute } from "./routes/features/featV2Icons";
+import { Feat3137Route } from "./routes/features/feat3137";
+import Feat3306Route from "./routes/features/feat3306";
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);
@@ -104,7 +110,9 @@ root.render(
} />
} />
} />
+ } />
} />
+ } />
} />
} />
@@ -118,14 +126,22 @@ root.render(
} />
} />
} />
- } />
+ }
+ />
} />
- } />
+ } />
} />
} />
} />
} />
} />
+ } />
+ } />
+ } />
+ } />
+ } />
diff --git a/apps/prs/react/src/routes/bugs/bug3232.tsx b/apps/prs/react/src/routes/bugs/bug3232.tsx
new file mode 100644
index 0000000000..bfcb4ce147
--- /dev/null
+++ b/apps/prs/react/src/routes/bugs/bug3232.tsx
@@ -0,0 +1,163 @@
+import {
+ GoabBlock,
+ GoabText,
+ GoabDivider,
+ GoabDetails,
+ GoabLink,
+} from "@abgov/react-components";
+
+export function Bug3232Route() {
+ return (
+
+
+ Bug #3232: GoabText tag prop should auto-apply heading size
+
+
+
+
+
+ View on GitHub
+
+
+
+
+
+ When using GoabText with a heading tag (h1-h5) but without explicitly setting
+ the size prop, the component renders the semantic HTML element but doesn't
+ apply the design system typography styles. Instead, it falls back to browser
+ defaults, which don't match our design tokens.
+
+
+
+
+
+
+ Test Cases
+
+
+ Left column uses just tag. Center column uses tag + explicit size.
+ Right column uses just explicit size. They should all match.
+
+
+ Test 1: H1 → heading-xl
+
+
+ Heading XL
+ tag="h1"
+
+
+ Heading XL
+ tag="h1" size="heading-xl"
+
+
+ Heading XL
+ size="heading-xl"
+
+
+
+ Test 2: H2 → heading-l
+
+
+ Heading L
+ tag="h2"
+
+
+ Heading L
+ tag="h2" size="heading-l"
+
+
+ Heading L
+ size="heading-l"
+
+
+
+ Test 3: H3 → heading-m
+
+
+ Heading M
+ tag="h3"
+
+
+ Heading M
+ tag="h3" size="heading-m"
+
+
+ Heading M
+ size="heading-m"
+
+
+
+ Test 4: H4 → heading-s
+
+
+ Heading S
+ tag="h4"
+
+
+ Heading S
+ tag="h4" size="heading-s"
+
+
+ Heading S
+ size="heading-s"
+
+
+
+ Test 5: H5 → heading-xs
+
+
+ Heading XS
+ tag="h5"
+
+
+ Heading XS
+ tag="h5" size="heading-xs"
+
+
+ Heading XS
+ size="heading-xs"
+
+
+
+
+
+ Test 6: Non-heading tags (no auto-size)
+
+ These should remain unstyled unless size is explicitly set.
+
+
+
+
+ Paragraph with no size - should be unstyled
+ tag="p" (no size)
+
+
+ Paragraph with body-m size
+ tag="p" size="body-m"
+
+
+ Span with no size - should be unstyled
+ tag="span" (no size)
+
+
+
+
+
+ Test 7: Explicit size overrides tag default
+
+ Setting size explicitly should override the tag-based default.
+
+
+
+
+
+
diff --git a/docs/src/content/examples/ask-a-long-answer-question-with-a-maximum-word-count/angular.html b/docs/src/content/examples/ask-a-long-answer-question-with-a-maximum-word-count/angular.html
new file mode 100644
index 0000000000..e2aeea7e44
--- /dev/null
+++ b/docs/src/content/examples/ask-a-long-answer-question-with-a-maximum-word-count/angular.html
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/docs/src/content/examples/ask-a-long-answer-question-with-a-maximum-word-count/angular.ts b/docs/src/content/examples/ask-a-long-answer-question-with-a-maximum-word-count/angular.ts
new file mode 100644
index 0000000000..64e536db59
--- /dev/null
+++ b/docs/src/content/examples/ask-a-long-answer-question-with-a-maximum-word-count/angular.ts
@@ -0,0 +1,16 @@
+import { Component } from "@angular/core";
+import { FormBuilder, FormGroup } from "@angular/forms";
+
+@Component({
+ selector: "app-ask-a-long-answer-question",
+ templateUrl: "./angular.html",
+})
+export class AskALongAnswerQuestionComponent {
+ form!: FormGroup;
+
+ constructor(private fb: FormBuilder) {
+ this.form = this.fb.group({
+ program: [""],
+ });
+ }
+}
diff --git a/docs/src/content/examples/ask-a-long-answer-question-with-a-maximum-word-count/index.mdx b/docs/src/content/examples/ask-a-long-answer-question-with-a-maximum-word-count/index.mdx
new file mode 100644
index 0000000000..153bbd7ed4
--- /dev/null
+++ b/docs/src/content/examples/ask-a-long-answer-question-with-a-maximum-word-count/index.mdx
@@ -0,0 +1,32 @@
+---
+id: ask-a-long-answer-question-with-a-maximum-word-count
+title: Ask a long answer question with a maximum word count
+categories:
+ - forms
+scale: task
+userType: citizen
+tags:
+ - forms
+ - text-area
+ - validation
+ - word-count
+components:
+ - form-item
+ - text-area
+status: published
+---
+
+Restrict a long answer input to a maximum number of words or characters.
+
+## When to use
+
+Use this pattern when:
+- Collecting open-ended responses
+- You need to limit response length
+- Users benefit from seeing remaining word count
+
+## Considerations
+
+- Choose between word count or character count based on the use case
+- Provide clear guidance on expected response length
+- Show remaining count to help users gauge their response
diff --git a/docs/src/content/examples/ask-a-long-answer-question-with-a-maximum-word-count/react.tsx b/docs/src/content/examples/ask-a-long-answer-question-with-a-maximum-word-count/react.tsx
new file mode 100644
index 0000000000..57dd2f766f
--- /dev/null
+++ b/docs/src/content/examples/ask-a-long-answer-question-with-a-maximum-word-count/react.tsx
@@ -0,0 +1,23 @@
+import { useState } from "react";
+import { GoabFormItem, GoabTextarea } from "@abgov/react-components";
+
+export function AskALongAnswerQuestionWithAMaximumWordCount() {
+ const [value, setValue] = useState("");
+
+ return (
+
+ setValue(e.value)}
+ value={value}
+ width="100%"
+ rows={6}
+ maxCount={500}
+ countBy="word"
+ />
+
+ );
+}
diff --git a/docs/src/content/examples/ask-a-long-answer-question-with-a-maximum-word-count/web-components.html b/docs/src/content/examples/ask-a-long-answer-question-with-a-maximum-word-count/web-components.html
new file mode 100644
index 0000000000..c6ca29add5
--- /dev/null
+++ b/docs/src/content/examples/ask-a-long-answer-question-with-a-maximum-word-count/web-components.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
diff --git a/docs/src/content/examples/ask-a-user-for-a-birthday/angular.html b/docs/src/content/examples/ask-a-user-for-a-birthday/angular.html
new file mode 100644
index 0000000000..98c4ffef9f
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-a-birthday/angular.html
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/docs/src/content/examples/ask-a-user-for-a-birthday/angular.ts b/docs/src/content/examples/ask-a-user-for-a-birthday/angular.ts
new file mode 100644
index 0000000000..4373c7f240
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-a-birthday/angular.ts
@@ -0,0 +1,13 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-ask-for-birthday",
+ templateUrl: "./angular.html",
+})
+export class AskForBirthdayComponent {
+ birthdate: Date | undefined;
+
+ onDateChange(event: { value: Date }) {
+ this.birthdate = event.value;
+ }
+}
diff --git a/docs/src/content/examples/ask-a-user-for-a-birthday/index.mdx b/docs/src/content/examples/ask-a-user-for-a-birthday/index.mdx
new file mode 100644
index 0000000000..d5a66aa748
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-a-birthday/index.mdx
@@ -0,0 +1,36 @@
+---
+id: ask-a-user-for-a-birthday
+title: Ask a user for a birthday
+categories:
+ - forms
+scale: task
+userType: citizen
+tags:
+ - forms
+ - date-input
+ - ask-a-user-for
+components:
+ - form-item
+ - date-picker
+relatedExamples:
+ - ask-a-user-for-an-address
+accessibilityNotes: |
+ The date picker component handles accessibility automatically.
+ Ensure the form-item label clearly describes what date is being requested.
+status: published
+---
+
+Asks for a user's birthday using the date picker component.
+
+## When to use
+
+Use this pattern when you need to collect a date of birth for:
+- Age verification
+- Identity confirmation
+- Benefits eligibility
+
+## Considerations
+
+- Consider whether you really need exact birthday vs just year or age range
+- The date picker provides a consistent, accessible date selection experience
+- Users can type the date directly or use the calendar picker
diff --git a/docs/src/content/examples/ask-a-user-for-a-birthday/react.tsx b/docs/src/content/examples/ask-a-user-for-a-birthday/react.tsx
new file mode 100644
index 0000000000..522634e246
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-a-birthday/react.tsx
@@ -0,0 +1,17 @@
+import { useState } from "react";
+import { GoabDatePicker, GoabFormItem } from "@abgov/react-components";
+
+export function AskForBirthday() {
+ const [birthdate, setBirthdate] = useState(undefined);
+
+ return (
+
+ setBirthdate(e.value)}
+ />
+
+ );
+}
diff --git a/docs/src/content/examples/ask-a-user-for-a-birthday/web-components.html b/docs/src/content/examples/ask-a-user-for-a-birthday/web-components.html
new file mode 100644
index 0000000000..984684e17e
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-a-birthday/web-components.html
@@ -0,0 +1,10 @@
+
+
+
+
+
diff --git a/docs/src/content/examples/ask-a-user-for-an-address/angular.html b/docs/src/content/examples/ask-a-user-for-an-address/angular.html
new file mode 100644
index 0000000000..faa07868f0
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-an-address/angular.html
@@ -0,0 +1,36 @@
+What is your address?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Save and continue
+ Cancel
+
diff --git a/docs/src/content/examples/ask-a-user-for-an-address/angular.ts b/docs/src/content/examples/ask-a-user-for-an-address/angular.ts
new file mode 100644
index 0000000000..fe9b86c517
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-an-address/angular.ts
@@ -0,0 +1,24 @@
+import { Component } from "@angular/core";
+import { FormBuilder, FormGroup } from "@angular/forms";
+
+@Component({
+ selector: "app-ask-a-user-for-an-address",
+ templateUrl: "./angular.html",
+})
+export class AskAUserForAnAddressComponent {
+ form!: FormGroup;
+
+ constructor(private fb: FormBuilder) {
+ this.form = this.fb.group({
+ address: [""],
+ suite: [""],
+ city: [""],
+ province: [""],
+ postalCode: [""],
+ });
+ }
+
+ onClick() {
+ // Handle form submission
+ }
+}
diff --git a/docs/src/content/examples/ask-a-user-for-an-address/index.mdx b/docs/src/content/examples/ask-a-user-for-an-address/index.mdx
new file mode 100644
index 0000000000..bc813913e7
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-an-address/index.mdx
@@ -0,0 +1,40 @@
+---
+id: ask-a-user-for-an-address
+title: Ask a user for an address
+categories:
+ - forms
+scale: task
+userType: citizen
+tags:
+ - forms
+ - address
+ - location
+components:
+ - form-item
+ - input
+ - dropdown
+ - block
+ - button
+ - button-group
+ - text
+figmaUrl: https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6304-43250
+relatedExamples:
+ - ask-a-user-for-a-birthday
+status: published
+---
+
+Collect a complete mailing address from the user, including fields like street, city, and postal code.
+
+## When to use
+
+Use this pattern when:
+- Collecting mailing addresses for correspondence
+- Gathering location information for services
+- Users need to provide physical address details
+
+## Considerations
+
+- Pre-select the most common province/territory
+- Use appropriate field widths (postal code is always 7 characters)
+- Consider address autocomplete for improved UX
+- Group related fields (province and postal code on same row)
diff --git a/docs/src/content/examples/ask-a-user-for-an-address/react.tsx b/docs/src/content/examples/ask-a-user-for-an-address/react.tsx
new file mode 100644
index 0000000000..667d357909
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-an-address/react.tsx
@@ -0,0 +1,92 @@
+import { useState } from "react";
+import {
+ GoabBlock,
+ GoabButton,
+ GoabButtonGroup,
+ GoabDropdown,
+ GoabDropdownItem,
+ GoabFormItem,
+ GoabInput,
+ GoabText,
+} from "@abgov/react-components";
+
+export function AskAUserForAnAddress() {
+ const [address, setAddress] = useState("");
+ const [suite, setSuite] = useState("");
+ const [city, setCity] = useState("");
+ const [province, setProvince] = useState("");
+ const [postalCode, setPostalCode] = useState("");
+
+ return (
+ <>
+ What is your address?
+
+ setAddress(e.value)}
+ width="100%"
+ />
+
+
+ setSuite(e.value)}
+ width="100%"
+ />
+
+
+ setCity(e.value)}
+ width="100%"
+ />
+
+
+
+ setProvince(e.value ?? "")}
+ name="province"
+ value={province}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ setPostalCode(e.value)}
+ width="7ch"
+ />
+
+
+
+ {}}>
+ Save and continue
+
+ {}}>
+ Cancel
+
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/ask-a-user-for-an-address/web-components.html b/docs/src/content/examples/ask-a-user-for-an-address/web-components.html
new file mode 100644
index 0000000000..fb7572a154
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-an-address/web-components.html
@@ -0,0 +1,42 @@
+What is your address?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Save and continue
+ Cancel
+
+
+
diff --git a/docs/src/content/examples/ask-a-user-for-an-indian-registration-number/angular.html b/docs/src/content/examples/ask-a-user-for-an-indian-registration-number/angular.html
new file mode 100644
index 0000000000..b735d0bc88
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-an-indian-registration-number/angular.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/examples/ask-a-user-for-an-indian-registration-number/angular.ts b/docs/src/content/examples/ask-a-user-for-an-indian-registration-number/angular.ts
new file mode 100644
index 0000000000..3aad233b35
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-an-indian-registration-number/angular.ts
@@ -0,0 +1,18 @@
+import { Component } from "@angular/core";
+import { FormBuilder, FormGroup } from "@angular/forms";
+
+@Component({
+ selector: "app-ask-a-user-for-an-indian-registration-number",
+ templateUrl: "./angular.html",
+})
+export class AskAUserForAnIndianRegistrationNumberComponent {
+ form!: FormGroup;
+
+ constructor(private fb: FormBuilder) {
+ this.form = this.fb.group({
+ bandNo: [""],
+ family: [""],
+ position: [""],
+ });
+ }
+}
diff --git a/docs/src/content/examples/ask-a-user-for-an-indian-registration-number/index.mdx b/docs/src/content/examples/ask-a-user-for-an-indian-registration-number/index.mdx
new file mode 100644
index 0000000000..823fa7a9b7
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-an-indian-registration-number/index.mdx
@@ -0,0 +1,34 @@
+---
+id: ask-a-user-for-an-indian-registration-number
+title: Ask a user for an Indian registration number
+categories:
+ - forms
+scale: task
+userType: citizen
+tags:
+ - forms
+ - identity
+ - registration
+components:
+ - form-item
+ - input
+ - block
+figmaUrl: https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=1896-179631
+status: published
+---
+
+Request a user's Indian registration number with appropriate validation and context.
+
+## When to use
+
+Use this pattern when:
+- Collecting Indigenous identity information
+- The registration number is required for benefits or services
+- You need to validate the format (3-digit band, up to 5-digit family, 2-digit position)
+
+## Considerations
+
+- Use separate fields for each component of the number
+- Set appropriate field widths to hint at expected input length
+- Provide clear help text for each field
+- Be respectful of the cultural significance of this information
diff --git a/docs/src/content/examples/ask-a-user-for-an-indian-registration-number/react.tsx b/docs/src/content/examples/ask-a-user-for-an-indian-registration-number/react.tsx
new file mode 100644
index 0000000000..735f500c14
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-an-indian-registration-number/react.tsx
@@ -0,0 +1,42 @@
+import { useState } from "react";
+import { GoabBlock, GoabFormItem, GoabInput } from "@abgov/react-components";
+
+export function AskAUserForAnIndianRegistrationNumber() {
+ const [bandNo, setBandNo] = useState("");
+ const [family, setFamily] = useState("");
+ const [position, setPosition] = useState("");
+
+ return (
+
+
+
+ setBandNo(e.value)}
+ value={bandNo}
+ name="bandNo"
+ width="88px"
+ maxLength={3}
+ />
+
+
+ setFamily(e.value)}
+ value={family}
+ name="family"
+ width="105px"
+ maxLength={5}
+ />
+
+
+ setPosition(e.value)}
+ value={position}
+ name="position"
+ width="71px"
+ maxLength={2}
+ />
+
+
+
+ );
+}
diff --git a/docs/src/content/examples/ask-a-user-for-an-indian-registration-number/web-components.html b/docs/src/content/examples/ask-a-user-for-an-indian-registration-number/web-components.html
new file mode 100644
index 0000000000..041de90ae8
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-an-indian-registration-number/web-components.html
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/examples/ask-a-user-for-direct-deposit-information/angular.html b/docs/src/content/examples/ask-a-user-for-direct-deposit-information/angular.html
new file mode 100644
index 0000000000..116b132858
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-direct-deposit-information/angular.html
@@ -0,0 +1,49 @@
+Direct deposit information
+
+ Find this information on your bank's website or on your personal cheques.
+ Contact your bank if you can't find this information.
+
+
+
+ Below is an example of where you can find the required bank information on a personal cheque.
+
+
+
+
+ Save and continue
+
diff --git a/docs/src/content/examples/ask-a-user-for-direct-deposit-information/angular.ts b/docs/src/content/examples/ask-a-user-for-direct-deposit-information/angular.ts
new file mode 100644
index 0000000000..d8439f566b
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-direct-deposit-information/angular.ts
@@ -0,0 +1,18 @@
+import { Component } from "@angular/core";
+import { FormBuilder, FormGroup } from "@angular/forms";
+
+@Component({
+ selector: "app-ask-a-user-for-direct-deposit-information",
+ templateUrl: "./angular.html",
+})
+export class AskAUserForDirectDepositInformationComponent {
+ form!: FormGroup;
+
+ constructor(private fb: FormBuilder) {
+ this.form = this.fb.group({
+ bankNumber: [""],
+ transitNumber: [""],
+ accountNumber: [""],
+ });
+ }
+}
diff --git a/docs/src/content/examples/ask-a-user-for-direct-deposit-information/index.mdx b/docs/src/content/examples/ask-a-user-for-direct-deposit-information/index.mdx
new file mode 100644
index 0000000000..38421b8ac6
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-direct-deposit-information/index.mdx
@@ -0,0 +1,35 @@
+---
+id: ask-a-user-for-direct-deposit-information
+title: Ask a user for direct deposit information
+categories:
+ - forms
+scale: task
+userType: citizen
+tags:
+ - forms
+ - banking
+ - financial
+components:
+ - form-item
+ - input
+ - details
+ - text
+figmaUrl: https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=1896-179620
+status: published
+---
+
+Gather banking details from users to enable direct deposit, including account number and financial institution information.
+
+## When to use
+
+Use this pattern when:
+- Setting up direct deposit for payments or refunds
+- Collecting banking information for recurring transactions
+- Users need to provide financial institution details
+
+## Considerations
+
+- Provide clear help text about where to find each number
+- Use the details component to show visual guidance (cheque image)
+- Set appropriate field widths based on expected input length
+- Be clear about security and how the information will be used
diff --git a/docs/src/content/examples/ask-a-user-for-direct-deposit-information/react.tsx b/docs/src/content/examples/ask-a-user-for-direct-deposit-information/react.tsx
new file mode 100644
index 0000000000..675b471bb1
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-direct-deposit-information/react.tsx
@@ -0,0 +1,71 @@
+import { useState } from "react";
+import { GoabButton, GoabDetails, GoabFormItem, GoabInput, GoabText } from "@abgov/react-components";
+
+export function AskAUserForDirectDepositInformation() {
+ const [bankNumber, setBankNumber] = useState("");
+ const [transitNumber, setTransitNumber] = useState("");
+ const [accountNumber, setAccountNumber] = useState("");
+
+ return (
+ <>
+ Direct deposit information
+
+ Find this information on your bank's website or on your personal cheques.
+ Contact your bank if you can't find this information.
+
+
+
+
+ Below is an example of where you can find the required bank information
+ on a personal cheque.
+
+
+
+
+
+ Save and continue
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/ask-a-user-for-direct-deposit-information/web-components.html b/docs/src/content/examples/ask-a-user-for-direct-deposit-information/web-components.html
new file mode 100644
index 0000000000..430c542b22
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-direct-deposit-information/web-components.html
@@ -0,0 +1,57 @@
+Direct deposit information
+
+ Find this information on your bank's website or on your personal cheques.
+ Contact your bank if you can't find this information.
+
+
+
+ Below is an example of where you can find the required bank information on a personal cheque.
+
+
+
+
+ Save and continue
+
+
+
diff --git a/docs/src/content/examples/ask-a-user-for-dollar-amounts/angular.html b/docs/src/content/examples/ask-a-user-for-dollar-amounts/angular.html
new file mode 100644
index 0000000000..1fd7eeb0fc
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-dollar-amounts/angular.html
@@ -0,0 +1,17 @@
+
diff --git a/docs/src/content/examples/ask-a-user-for-dollar-amounts/angular.ts b/docs/src/content/examples/ask-a-user-for-dollar-amounts/angular.ts
new file mode 100644
index 0000000000..9fabb800a7
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-dollar-amounts/angular.ts
@@ -0,0 +1,14 @@
+import { Component } from "@angular/core";
+import { FormControl, FormGroup } from "@angular/forms";
+
+@Component({
+ selector: "app-ask-a-user-for-dollar-amounts",
+ templateUrl: "./angular.html",
+})
+export class AskAUserForDollarAmountsComponent {
+ costFormGroup = new FormGroup({
+ tuitionFeeAmount: new FormControl(""),
+ suppliesAmount: new FormControl(""),
+ othersAmount: new FormControl(""),
+ });
+}
diff --git a/docs/src/content/examples/ask-a-user-for-dollar-amounts/index.mdx b/docs/src/content/examples/ask-a-user-for-dollar-amounts/index.mdx
new file mode 100644
index 0000000000..de775abc1e
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-dollar-amounts/index.mdx
@@ -0,0 +1,33 @@
+---
+id: ask-a-user-for-dollar-amounts
+title: Ask a user for dollar amounts
+categories:
+ - forms
+scale: task
+userType: citizen
+tags:
+ - forms
+ - currency
+ - financial
+components:
+ - form-item
+ - input
+figmaUrl: https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=1896-179629
+status: published
+---
+
+Prompt users to enter monetary values using a consistent input format that supports validation and currency symbols.
+
+## When to use
+
+Use this pattern when:
+- Collecting cost or expense information
+- Users need to enter multiple monetary values
+- You want consistent currency formatting
+
+## Considerations
+
+- Use the `leadingContent` prop to show the $ symbol
+- Consider if decimal places are needed
+- Group related amounts together
+- Provide clear labels for each amount field
diff --git a/docs/src/content/examples/ask-a-user-for-dollar-amounts/react.tsx b/docs/src/content/examples/ask-a-user-for-dollar-amounts/react.tsx
new file mode 100644
index 0000000000..eb1a36fa90
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-dollar-amounts/react.tsx
@@ -0,0 +1,37 @@
+import { useState } from "react";
+import { GoabFormItem, GoabInput } from "@abgov/react-components";
+
+export function AskAUserForDollarAmounts() {
+ const [tuitionAmount, setTuitionAmount] = useState("");
+ const [suppliesAmount, setSuppliesAmount] = useState("");
+ const [othersAmount, setOthersAmount] = useState("");
+
+ return (
+ <>
+
+ setTuitionAmount(e.value)}
+ value={tuitionAmount}
+ name="tuitionAmount"
+ leadingContent="$"
+ />
+
+
+ setSuppliesAmount(e.value)}
+ value={suppliesAmount}
+ name="suppliesAmount"
+ leadingContent="$"
+ />
+
+
+ setOthersAmount(e.value)}
+ value={othersAmount}
+ name="othersAmount"
+ leadingContent="$"
+ />
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/ask-a-user-for-dollar-amounts/web-components.html b/docs/src/content/examples/ask-a-user-for-dollar-amounts/web-components.html
new file mode 100644
index 0000000000..adfc30d024
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-for-dollar-amounts/web-components.html
@@ -0,0 +1,25 @@
+
+
+
diff --git a/docs/src/content/examples/ask-a-user-one-question-at-a-time/angular.html b/docs/src/content/examples/ask-a-user-one-question-at-a-time/angular.html
new file mode 100644
index 0000000000..c96c5d8e9f
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-one-question-at-a-time/angular.html
@@ -0,0 +1,16 @@
+
+ Back
+
+
+
+
+
+
+
+
+ Save and continue
+
diff --git a/docs/src/content/examples/ask-a-user-one-question-at-a-time/angular.ts b/docs/src/content/examples/ask-a-user-one-question-at-a-time/angular.ts
new file mode 100644
index 0000000000..a80849ae80
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-one-question-at-a-time/angular.ts
@@ -0,0 +1,33 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-ask-a-user-one-question-at-a-time",
+ templateUrl: "./angular.html",
+ styles: [`
+ a.back-link::before {
+ content: "";
+ display: inline-block;
+ width: 42px;
+ height: 24px;
+ vertical-align: middle;
+ background: url('data:image/svg+xml,') center center no-repeat;
+ }
+
+ a.back-link:visited::before,
+ a.back-link:hover::before {
+ background: url('data:image/svg+xml,') center center no-repeat;
+ }
+
+ a.back-link {
+ margin-top: var(--goa-space-m);
+ }
+ `]
+})
+export class AskAUserOneQuestionAtATimeComponent {
+ selectedValue = "";
+
+ onSchoolChange(event: Event): void {
+ const detail = (event as CustomEvent).detail;
+ this.selectedValue = detail.value;
+ }
+}
diff --git a/docs/src/content/examples/ask-a-user-one-question-at-a-time/index.mdx b/docs/src/content/examples/ask-a-user-one-question-at-a-time/index.mdx
new file mode 100644
index 0000000000..0b63913f52
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-one-question-at-a-time/index.mdx
@@ -0,0 +1,35 @@
+---
+id: ask-a-user-one-question-at-a-time
+title: Ask a user one question at a time
+categories:
+ - forms
+scale: page
+userType: citizen
+tags:
+ - forms
+ - questions
+ - public-form
+components:
+ - form-item
+ - radio-group
+ - radio-item
+ - button
+status: published
+---
+
+Ask a user one question at a time.
+
+## When to use
+
+Use this pattern when:
+- Building a public-facing form for citizens
+- You want to reduce cognitive load by focusing on one question
+- The question requires careful consideration from the user
+- Following the one-question-per-page pattern for government services
+
+## Considerations
+
+- Include a back link to allow users to navigate to previous questions
+- Use a large label size to make the question prominent
+- Provide help text when the question may need clarification
+- Use a clear call-to-action button to progress
diff --git a/docs/src/content/examples/ask-a-user-one-question-at-a-time/react.tsx b/docs/src/content/examples/ask-a-user-one-question-at-a-time/react.tsx
new file mode 100644
index 0000000000..3b5ffc73c3
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-one-question-at-a-time/react.tsx
@@ -0,0 +1,30 @@
+import {
+ GoabButton,
+ GoabFormItem,
+ GoabLink,
+ GoabRadioGroup,
+ GoabRadioItem
+} from "@abgov/react-components";
+
+export function AskAUserOneQuestionAtATime() {
+ return (
+ <>
+
+ Back
+
+
+ {}}>
+
+
+
+
+
+ Save and continue
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/ask-a-user-one-question-at-a-time/web-components.html b/docs/src/content/examples/ask-a-user-one-question-at-a-time/web-components.html
new file mode 100644
index 0000000000..a3914c4be7
--- /dev/null
+++ b/docs/src/content/examples/ask-a-user-one-question-at-a-time/web-components.html
@@ -0,0 +1,22 @@
+
+ Back
+
+
+
+
+
+
+
+
+ Save and continue
+
+
+
diff --git a/docs/src/content/examples/basic-page-layout/angular.html b/docs/src/content/examples/basic-page-layout/angular.html
new file mode 100644
index 0000000000..214d757343
--- /dev/null
+++ b/docs/src/content/examples/basic-page-layout/angular.html
@@ -0,0 +1,25 @@
+
+
+
+
+ Sign in
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/examples/basic-page-layout/angular.ts b/docs/src/content/examples/basic-page-layout/angular.ts
new file mode 100644
index 0000000000..a3e9c5788b
--- /dev/null
+++ b/docs/src/content/examples/basic-page-layout/angular.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-basic-page-layout",
+ templateUrl: "./angular.html",
+})
+export class BasicPageLayoutComponent {}
diff --git a/docs/src/content/examples/basic-page-layout/index.mdx b/docs/src/content/examples/basic-page-layout/index.mdx
new file mode 100644
index 0000000000..4937d9927d
--- /dev/null
+++ b/docs/src/content/examples/basic-page-layout/index.mdx
@@ -0,0 +1,37 @@
+---
+id: basic-page-layout
+title: Basic page layout
+categories:
+ - content-layout
+scale: page
+userType: both
+tags:
+ - layout
+ - page-structure
+ - template
+components:
+ - microsite-header
+ - app-header
+ - footer
+ - page-block
+ - skeleton
+ - grid
+status: published
+fullWidth: true
+---
+
+A basic page template to use as a starting point.
+
+## When to use
+
+Use this pattern when:
+- Starting a new government service or application
+- You need a standard page structure with header and footer
+- Building pages that need consistent layout across your service
+
+## Considerations
+
+- Include both microsite header and app header for proper government branding
+- Use page-block to constrain content width appropriately
+- The skeleton loaders show content areas during loading states
+- Always include an app footer for consistent navigation and required links
diff --git a/docs/src/content/examples/basic-page-layout/react.tsx b/docs/src/content/examples/basic-page-layout/react.tsx
new file mode 100644
index 0000000000..bab53a951b
--- /dev/null
+++ b/docs/src/content/examples/basic-page-layout/react.tsx
@@ -0,0 +1,39 @@
+import {
+ GoabAppFooter,
+ GoabAppHeader,
+ GoabGrid,
+ GoabMicrositeHeader,
+ GoabOneColumnLayout,
+ GoabPageBlock,
+ GoabSkeleton
+} from "@abgov/react-components";
+
+export function BasicPageLayout() {
+ return (
+
+
+
+
+ Sign in
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/examples/button-with-icon/angular.html b/docs/src/content/examples/button-with-icon/angular.html
new file mode 100644
index 0000000000..606070a1ad
--- /dev/null
+++ b/docs/src/content/examples/button-with-icon/angular.html
@@ -0,0 +1,5 @@
+
+ Go back
+ Continue
+ Add item
+
diff --git a/docs/src/content/examples/button-with-icon/index.mdx b/docs/src/content/examples/button-with-icon/index.mdx
new file mode 100644
index 0000000000..542ea83e11
--- /dev/null
+++ b/docs/src/content/examples/button-with-icon/index.mdx
@@ -0,0 +1,37 @@
+---
+id: button-with-icon
+title: Button with Icon
+categories:
+ - inputs-and-actions
+scale: interaction
+userType: both
+tags:
+ - icons
+ - buttons
+ - actions
+components:
+ - button
+ - button-group
+ - icon
+accessibilityNotes: |
+ When using icons in buttons, the button text provides the accessible name.
+ The icon is decorative and should be hidden from screen readers with aria-hidden.
+figmaUrl: https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?t=s7AqNIWl2ZvcUSxt-0
+status: published
+---
+
+Shows how to add leading or trailing icons to buttons for enhanced visual communication.
+
+## Use cases
+
+- Back navigation buttons with arrow icon
+- Add buttons with plus icon
+- Download buttons with download icon
+- External link buttons with external icon
+
+## Considerations
+
+- Keep icon and text semantically aligned
+- Don't use icons just for decoration
+- Leading icons for actions that "go back" or "add"
+- Trailing icons for actions that "go forward" or "external"
diff --git a/docs/src/content/examples/button-with-icon/react.tsx b/docs/src/content/examples/button-with-icon/react.tsx
new file mode 100644
index 0000000000..1f8406a8c9
--- /dev/null
+++ b/docs/src/content/examples/button-with-icon/react.tsx
@@ -0,0 +1,11 @@
+import { GoabButton, GoabButtonGroup } from "@abgov/react-components";
+
+export function ButtonWithIcon() {
+ return (
+
+ Go back
+ Continue
+ Add item
+
+ );
+}
diff --git a/docs/src/content/examples/button-with-icon/web-components.html b/docs/src/content/examples/button-with-icon/web-components.html
new file mode 100644
index 0000000000..a7fd47865e
--- /dev/null
+++ b/docs/src/content/examples/button-with-icon/web-components.html
@@ -0,0 +1,5 @@
+
+ Go back
+ Continue
+ Add item
+
diff --git a/docs/src/content/examples/card-grid/angular.html b/docs/src/content/examples/card-grid/angular.html
new file mode 100644
index 0000000000..4c02c8d9f6
--- /dev/null
+++ b/docs/src/content/examples/card-grid/angular.html
@@ -0,0 +1,61 @@
+
+
+
+ Waitlist submission
+
+
+ Enter and maintain information about the households waiting for affordable housing
+ with your organization.
+
+
+
+
+
+ Lodge assistance program
+
+
+ Keep track of the individuals who are placed in lodges and may qualify for the Lodge
+ Assistance Program subsidy.
+
+
+
+
+
+ Education Support
+
+
+ Explore educational resources, enroll in courses, and track your academic progress
+ effortlessly.
+
+
+
+
+
+ Social Assistance
+
+
+ Learn about available support programs, apply for financial aid, and access community
+ resources.
+
+
+
+
+
+ Employment Opportunity
+
+
+ Search for job openings, access career development tools, and receive
+ employment-related updates.
+
+
+
+
+
+ Housing Assistance
+
+
+ Find affordable housing options, apply for housing subsidies, and report maintenance
+ issues seamlessly.
+
+
+
diff --git a/docs/src/content/examples/card-grid/angular.ts b/docs/src/content/examples/card-grid/angular.ts
new file mode 100644
index 0000000000..180759b7c5
--- /dev/null
+++ b/docs/src/content/examples/card-grid/angular.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-card-grid",
+ templateUrl: "./angular.html",
+})
+export class CardGridComponent {}
diff --git a/docs/src/content/examples/card-grid/index.mdx b/docs/src/content/examples/card-grid/index.mdx
new file mode 100644
index 0000000000..c411dad89f
--- /dev/null
+++ b/docs/src/content/examples/card-grid/index.mdx
@@ -0,0 +1,36 @@
+---
+id: card-grid
+title: Card grid
+categories:
+ - content-layout
+scale: task
+userType: both
+tags:
+ - cards
+ - grid
+ - navigation
+ - dashboard
+components:
+ - container
+ - grid
+ - link
+ - text
+status: published
+---
+
+Display multiple cards in a grid layout, each containing related content or actions.
+
+## When to use
+
+Use this pattern when:
+- Presenting multiple related items in a scannable format
+- Creating a dashboard or landing page with navigable sections
+- Users need to choose between several options or services
+- Content can be grouped into discrete, equally-weighted items
+
+## Considerations
+
+- Use consistent card heights where possible for visual alignment
+- Link titles should clearly describe where the user will navigate
+- Keep descriptions concise to maintain scannability
+- Use the grid's minChildWidth to ensure cards wrap appropriately on smaller screens
diff --git a/docs/src/content/examples/card-grid/react.tsx b/docs/src/content/examples/card-grid/react.tsx
new file mode 100644
index 0000000000..ec42676419
--- /dev/null
+++ b/docs/src/content/examples/card-grid/react.tsx
@@ -0,0 +1,67 @@
+import { GoabContainer, GoabGrid, GoabLink, GoabText } from "@abgov/react-components";
+
+export function CardGrid() {
+ return (
+
+
+
+ Waitlist submission
+
+
+ Enter and maintain information about the households waiting for affordable housing
+ with your organization.
+
+
+
+
+
+ Lodge assistance program
+
+
+ Keep track of the individuals who are placed in lodges and may qualify for the Lodge
+ Assistance Program subsidy.
+
+
+
+
+
+ Education Support
+
+
+ Explore educational resources, enroll in courses, and track your academic progress
+ effortlessly.
+
+
+
+
+
+ Social Assistance
+
+
+ Learn about available support programs, apply for financial aid, and access community
+ resources.
+
+
+
+
+
+ Employment Opportunity
+
+
+ Search for job openings, access career development tools, and receive
+ employment-related updates.
+
+
+
+
+
+ Housing Assistance
+
+
+ Find affordable housing options, apply for housing subsidies, and report maintenance
+ issues seamlessly.
+
+
+
+ );
+}
diff --git a/docs/src/content/examples/card-grid/web-components.html b/docs/src/content/examples/card-grid/web-components.html
new file mode 100644
index 0000000000..735776b1f1
--- /dev/null
+++ b/docs/src/content/examples/card-grid/web-components.html
@@ -0,0 +1,61 @@
+
+
+
+ Waitlist submission
+
+
+ Enter and maintain information about the households waiting for affordable housing
+ with your organization.
+
+
+
+
+
+ Lodge assistance program
+
+
+ Keep track of the individuals who are placed in lodges and may qualify for the Lodge
+ Assistance Program subsidy.
+
+
+
+
+
+ Education Support
+
+
+ Explore educational resources, enroll in courses, and track your academic progress
+ effortlessly.
+
+
+
+
+
+ Social Assistance
+
+
+ Learn about available support programs, apply for financial aid, and access community
+ resources.
+
+
+
+
+
+ Employment Opportunity
+
+
+ Search for job openings, access career development tools, and receive
+ employment-related updates.
+
+
+
+
+
+ Housing Assistance
+
+
+ Find affordable housing options, apply for housing subsidies, and report maintenance
+ issues seamlessly.
+
+
+
diff --git a/docs/src/content/examples/card-view-of-case-files/angular.html b/docs/src/content/examples/card-view-of-case-files/angular.html
new file mode 100644
index 0000000000..37ceebf1e9
--- /dev/null
+++ b/docs/src/content/examples/card-view-of-case-files/angular.html
@@ -0,0 +1,38 @@
+
+
+
diff --git a/docs/src/content/examples/card-view-of-case-files/angular.ts b/docs/src/content/examples/card-view-of-case-files/angular.ts
new file mode 100644
index 0000000000..90b4373b93
--- /dev/null
+++ b/docs/src/content/examples/card-view-of-case-files/angular.ts
@@ -0,0 +1,16 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-card-view-of-case-files",
+ templateUrl: "./angular.html",
+ styles: [`
+ .case-file-row {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ align-items: center;
+ gap: var(--goa-space-m);
+ }
+ `]
+})
+export class CardViewOfCaseFilesComponent {}
diff --git a/docs/src/content/examples/card-view-of-case-files/index.mdx b/docs/src/content/examples/card-view-of-case-files/index.mdx
new file mode 100644
index 0000000000..90fe7eba92
--- /dev/null
+++ b/docs/src/content/examples/card-view-of-case-files/index.mdx
@@ -0,0 +1,36 @@
+---
+id: card-view-of-case-files
+title: Card view of case files
+categories:
+ - content-layout
+scale: task
+userType: worker
+tags:
+ - cards
+ - case-management
+ - status
+ - list
+components:
+ - container
+ - block
+ - badge
+ - button
+status: published
+---
+
+Present a visual overview of individual case files in a card format for scanning and access.
+
+## When to use
+
+Use this pattern when:
+- Displaying a list of case files or records that workers need to manage
+- Each record has a status that needs to be clearly visible
+- Users need quick access to view or edit individual records
+- Showing summary information with actions for each item
+
+## Considerations
+
+- Use badges to clearly indicate the status of each case
+- Provide consistent action buttons (Edit, View) based on the case status
+- Include key identifying information like dates and fiscal years
+- Consider responsive layout for smaller screens
diff --git a/docs/src/content/examples/card-view-of-case-files/react.tsx b/docs/src/content/examples/card-view-of-case-files/react.tsx
new file mode 100644
index 0000000000..1efe2aee3f
--- /dev/null
+++ b/docs/src/content/examples/card-view-of-case-files/react.tsx
@@ -0,0 +1,56 @@
+import { GoabBadge, GoabBlock, GoabButton, GoabContainer, GoabText } from "@abgov/react-components";
+
+export function CardViewOfCaseFiles() {
+ return (
+ <>
+
+
+
+
+
diff --git a/docs/src/content/examples/communicate-a-future-service-outage/angular.html b/docs/src/content/examples/communicate-a-future-service-outage/angular.html
new file mode 100644
index 0000000000..c4f6370bca
--- /dev/null
+++ b/docs/src/content/examples/communicate-a-future-service-outage/angular.html
@@ -0,0 +1,5 @@
+
+ Our system will be under maintenance from Thursday, September 15, 2025 at 10 pm
+ to Friday, September 16, 2025 at 10 am. If you have questions or concerns,
+ contact us at support@example.com.
+
diff --git a/docs/src/content/examples/communicate-a-future-service-outage/angular.ts b/docs/src/content/examples/communicate-a-future-service-outage/angular.ts
new file mode 100644
index 0000000000..2730b931ec
--- /dev/null
+++ b/docs/src/content/examples/communicate-a-future-service-outage/angular.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-communicate-a-future-service-outage",
+ templateUrl: "./angular.html",
+})
+export class CommunicateAFutureServiceOutageComponent {}
diff --git a/docs/src/content/examples/communicate-a-future-service-outage/index.mdx b/docs/src/content/examples/communicate-a-future-service-outage/index.mdx
new file mode 100644
index 0000000000..cc87d87bcd
--- /dev/null
+++ b/docs/src/content/examples/communicate-a-future-service-outage/index.mdx
@@ -0,0 +1,34 @@
+---
+id: communicate-a-future-service-outage
+title: Communicate a future service outage
+categories:
+ - feedback-and-alerts
+scale: task
+userType: both
+tags:
+ - notification
+ - maintenance
+ - alerts
+ - system-status
+components:
+ - notification
+status: published
+fullWidth: true
+---
+
+Display a clear message to inform users about an upcoming service outage, including the date, time, and expected impact on service availability.
+
+## When to use
+
+Use this pattern when:
+- Scheduled maintenance will affect service availability
+- Users need advance notice about system downtime
+- You need to communicate specific dates and times for an outage
+- Users should know how to get support during the outage
+
+## Considerations
+
+- Use the "important" notification type to draw attention
+- Include specific dates, times, and duration of the outage
+- Provide contact information for questions or concerns
+- Place the notification prominently on affected pages
diff --git a/docs/src/content/examples/communicate-a-future-service-outage/react.tsx b/docs/src/content/examples/communicate-a-future-service-outage/react.tsx
new file mode 100644
index 0000000000..e98ed3ee12
--- /dev/null
+++ b/docs/src/content/examples/communicate-a-future-service-outage/react.tsx
@@ -0,0 +1,11 @@
+import { GoabNotification } from "@abgov/react-components";
+
+export function CommunicateAFutureServiceOutage() {
+ return (
+
+ Our system will be under maintenance from Thursday, September 15, 2025 at 10 pm
+ to Friday, September 16, 2025 at 10 am. If you have questions or concerns,
+ contact us at support@example.com.
+
+ );
+}
diff --git a/docs/src/content/examples/communicate-a-future-service-outage/web-components.html b/docs/src/content/examples/communicate-a-future-service-outage/web-components.html
new file mode 100644
index 0000000000..2f4fe99313
--- /dev/null
+++ b/docs/src/content/examples/communicate-a-future-service-outage/web-components.html
@@ -0,0 +1,5 @@
+
+ Our system will be under maintenance from Thursday, September 15, 2025 at 10 pm
+ to Friday, September 16, 2025 at 10 am. If you have questions or concerns,
+ contact us at support@example.com.
+
diff --git a/docs/src/content/examples/confirm-a-change/angular.html b/docs/src/content/examples/confirm-a-change/angular.html
new file mode 100644
index 0000000000..4373f53bb9
--- /dev/null
+++ b/docs/src/content/examples/confirm-a-change/angular.html
@@ -0,0 +1,23 @@
+Save and continue
+
+
+
+ Before
+ 123456 78 Ave NW, Edmonton, Alberta
+ After
+ 881 12 Ave NW, Edmonton, Alberta
+
+
+
+
+
+
+
+ Undo address change
+
+
+ Confirm
+
+
+
+
diff --git a/docs/src/content/examples/confirm-a-change/angular.ts b/docs/src/content/examples/confirm-a-change/angular.ts
new file mode 100644
index 0000000000..049cdff828
--- /dev/null
+++ b/docs/src/content/examples/confirm-a-change/angular.ts
@@ -0,0 +1,19 @@
+import { Component } from "@angular/core";
+import { GoabDatePickerOnChangeDetail } from "@abgov/ui-components-common";
+
+@Component({
+ selector: "app-confirm-a-change",
+ templateUrl: "./angular.html",
+})
+export class ConfirmAChangeComponent {
+ open = false;
+ effectiveDate = new Date();
+
+ toggleModal(): void {
+ this.open = !this.open;
+ }
+
+ onChangeEffectiveDate(event: GoabDatePickerOnChangeDetail): void {
+ this.effectiveDate = event.value as Date;
+ }
+}
diff --git a/docs/src/content/examples/confirm-a-change/index.mdx b/docs/src/content/examples/confirm-a-change/index.mdx
new file mode 100644
index 0000000000..640a317f4d
--- /dev/null
+++ b/docs/src/content/examples/confirm-a-change/index.mdx
@@ -0,0 +1,38 @@
+---
+id: confirm-a-change
+title: Confirm a change
+categories:
+ - inputs-and-actions
+scale: task
+userType: both
+tags:
+ - modal
+ - confirmation
+ - forms
+ - changes
+components:
+ - modal
+ - button
+ - button-group
+ - container
+ - form-item
+ - date-picker
+status: published
+---
+
+Ask the user to confirm a proposed change before it is applied.
+
+## When to use
+
+Use this pattern when:
+- A user has made changes that need explicit confirmation
+- You want to show a before/after comparison
+- The change includes additional options like an effective date
+- Users should have the opportunity to undo the change
+
+## Considerations
+
+- Show clear before and after states for the change
+- Provide an "undo" option alongside the confirm action
+- Include any relevant additional inputs (like effective date)
+- Use a secondary button for the cancel/undo action
diff --git a/docs/src/content/examples/confirm-a-change/react.tsx b/docs/src/content/examples/confirm-a-change/react.tsx
new file mode 100644
index 0000000000..0dc85da8ed
--- /dev/null
+++ b/docs/src/content/examples/confirm-a-change/react.tsx
@@ -0,0 +1,55 @@
+import { useState } from "react";
+import {
+ GoabButton,
+ GoabButtonGroup,
+ GoabContainer,
+ GoabDatePicker,
+ GoabFormItem,
+ GoabModal,
+ GoabText
+} from "@abgov/react-components";
+import { GoabDatePickerOnChangeDetail } from "@abgov/ui-components-common";
+
+export function ConfirmAChange() {
+ const [open, setOpen] = useState(false);
+ const [effectiveDate, setEffectiveDate] = useState(new Date());
+
+ const onChangeEffectiveDate = (detail: GoabDatePickerOnChangeDetail) => {
+ setEffectiveDate(detail.value as Date);
+ };
+
+ return (
+ <>
+ setOpen(true)}>Save and continue
+
+ setOpen(false)}
+ actions={
+
+ setOpen(false)}>
+ Undo address change
+
+ setOpen(false)}>
+ Confirm
+
+
+ }>
+
+ Before
+ 123456 78 Ave NW, Edmonton, Alberta
+ After
+ 881 12 Ave NW, Edmonton, Alberta
+
+
+
+
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/confirm-a-change/web-components.html b/docs/src/content/examples/confirm-a-change/web-components.html
new file mode 100644
index 0000000000..6b8d8ae334
--- /dev/null
+++ b/docs/src/content/examples/confirm-a-change/web-components.html
@@ -0,0 +1,54 @@
+Save and continue
+
+
+
+ Before
+ 123456 78 Ave NW, Edmonton, Alberta
+ After
+ 881 12 Ave NW, Edmonton, Alberta
+
+
+
+
+
+
+
+ Undo address change
+
+
+ Confirm
+
+
+
+
+
+
diff --git a/docs/src/content/examples/confirm-a-destructive-action/angular.html b/docs/src/content/examples/confirm-a-destructive-action/angular.html
new file mode 100644
index 0000000000..c496f58ed2
--- /dev/null
+++ b/docs/src/content/examples/confirm-a-destructive-action/angular.html
@@ -0,0 +1,10 @@
+Delete record
+
+
This action cannot be undone.
+
+
+ Cancel
+ Delete record
+
+
+
diff --git a/docs/src/content/examples/confirm-a-destructive-action/angular.ts b/docs/src/content/examples/confirm-a-destructive-action/angular.ts
new file mode 100644
index 0000000000..06b5bc2dba
--- /dev/null
+++ b/docs/src/content/examples/confirm-a-destructive-action/angular.ts
@@ -0,0 +1,13 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-confirm-a-destructive-action",
+ templateUrl: "./angular.html",
+})
+export class ConfirmADestructiveActionComponent {
+ open = false;
+
+ toggleModal(): void {
+ this.open = !this.open;
+ }
+}
diff --git a/docs/src/content/examples/confirm-a-destructive-action/index.mdx b/docs/src/content/examples/confirm-a-destructive-action/index.mdx
new file mode 100644
index 0000000000..565fb975cf
--- /dev/null
+++ b/docs/src/content/examples/confirm-a-destructive-action/index.mdx
@@ -0,0 +1,35 @@
+---
+id: confirm-a-destructive-action
+title: Confirm a destructive action
+categories:
+ - feedback-and-alerts
+scale: task
+userType: both
+tags:
+ - modal
+ - confirmation
+ - delete
+ - destructive
+components:
+ - modal
+ - button
+ - button-group
+status: published
+---
+
+Confirm a destructive action like deletion to prevent accidental data loss.
+
+## When to use
+
+Use this pattern when:
+- A user is about to delete data permanently
+- The action cannot be undone
+- You need to prevent accidental destructive actions
+- Data loss would have significant impact
+
+## Considerations
+
+- Use the destructive button variant to emphasize the danger
+- Clearly state that the action cannot be undone
+- Provide a cancel option that's easy to access
+- Use a tertiary button with a trash icon for the initial action
diff --git a/docs/src/content/examples/confirm-a-destructive-action/react.tsx b/docs/src/content/examples/confirm-a-destructive-action/react.tsx
new file mode 100644
index 0000000000..afe62b6884
--- /dev/null
+++ b/docs/src/content/examples/confirm-a-destructive-action/react.tsx
@@ -0,0 +1,37 @@
+import { useState } from "react";
+import { GoabButton, GoabButtonGroup, GoabModal } from "@abgov/react-components";
+
+export function ConfirmADestructiveAction() {
+ const [open, setOpen] = useState(false);
+
+ return (
+ <>
+ setOpen(true)}>
+ Delete record
+
+ setOpen(false)}
+ actions={
+
+ setOpen(false)}>
+ Cancel
+
+ setOpen(false)}>
+ Delete record
+
+
+ }>
+
This action cannot be undone.
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/confirm-a-destructive-action/web-components.html b/docs/src/content/examples/confirm-a-destructive-action/web-components.html
new file mode 100644
index 0000000000..a9a2dc0ec5
--- /dev/null
+++ b/docs/src/content/examples/confirm-a-destructive-action/web-components.html
@@ -0,0 +1,33 @@
+Delete record
+
+
This action cannot be undone.
+
+
+ Cancel
+ Delete record
+
+
+
+
+
diff --git a/docs/src/content/examples/confirm-before-navigating-away/angular.html b/docs/src/content/examples/confirm-before-navigating-away/angular.html
new file mode 100644
index 0000000000..017c7a9cae
--- /dev/null
+++ b/docs/src/content/examples/confirm-before-navigating-away/angular.html
@@ -0,0 +1,9 @@
+Open
+
+
+
+ Cancel
+ Change route
+
+
+
diff --git a/docs/src/content/examples/confirm-before-navigating-away/angular.ts b/docs/src/content/examples/confirm-before-navigating-away/angular.ts
new file mode 100644
index 0000000000..99421e1be5
--- /dev/null
+++ b/docs/src/content/examples/confirm-before-navigating-away/angular.ts
@@ -0,0 +1,26 @@
+import { Component } from "@angular/core";
+import { Router } from "@angular/router";
+
+@Component({
+ selector: "app-confirm-before-navigating-away",
+ templateUrl: "./angular.html",
+})
+export class ConfirmBeforeNavigatingAwayComponent {
+ open = false;
+
+ constructor(private router: Router) {}
+
+ onOpen(): void {
+ this.open = true;
+ }
+
+ onClose(): void {
+ this.open = false;
+ }
+
+ onChangeRoute(): void {
+ this.open = false;
+ // setTimeout will allow any modal transitions to be run
+ setTimeout(() => this.router.navigate(["/components"]), 0);
+ }
+}
diff --git a/docs/src/content/examples/confirm-before-navigating-away/index.mdx b/docs/src/content/examples/confirm-before-navigating-away/index.mdx
new file mode 100644
index 0000000000..4d50ea5754
--- /dev/null
+++ b/docs/src/content/examples/confirm-before-navigating-away/index.mdx
@@ -0,0 +1,35 @@
+---
+id: confirm-before-navigating-away
+title: Confirm before navigating away
+categories:
+ - feedback-and-alerts
+scale: task
+userType: worker
+tags:
+ - modal
+ - navigation
+ - confirmation
+ - routing
+components:
+ - modal
+ - button
+ - button-group
+status: published
+---
+
+Prompt the user in a modal before navigating to a new route to preserve context.
+
+## When to use
+
+Use this pattern when:
+- The user has unsaved changes that would be lost
+- Navigation would interrupt an important workflow
+- You need to confirm the user's intent to leave the page
+- Context or data would be lost on navigation
+
+## Considerations
+
+- Allow users to cancel and stay on the current page
+- Use setTimeout for route changes after modal closes for smooth transitions
+- The secondary button should cancel the navigation
+- The primary button confirms the route change
diff --git a/docs/src/content/examples/confirm-before-navigating-away/react.tsx b/docs/src/content/examples/confirm-before-navigating-away/react.tsx
new file mode 100644
index 0000000000..3201c7caee
--- /dev/null
+++ b/docs/src/content/examples/confirm-before-navigating-away/react.tsx
@@ -0,0 +1,34 @@
+import { useState } from "react";
+import { GoabButton, GoabButtonGroup, GoabModal } from "@abgov/react-components";
+
+export function ConfirmBeforeNavigatingAway() {
+ const [open, setOpen] = useState(false);
+
+ const handleChangeRoute = () => {
+ setOpen(false);
+ // In a real app, you would use your router's navigate function
+ // setTimeout(() => navigate("/some-path"), 300);
+ console.log("Navigating to new route...");
+ };
+
+ return (
+ <>
+ setOpen(true)}>Open
+ setOpen(false)}
+ actions={
+
+ setOpen(false)}>
+ Cancel
+
+
+ Change route
+
+
+ }
+ />
+ >
+ );
+}
diff --git a/docs/src/content/examples/confirm-before-navigating-away/web-components.html b/docs/src/content/examples/confirm-before-navigating-away/web-components.html
new file mode 100644
index 0000000000..0193e74df3
--- /dev/null
+++ b/docs/src/content/examples/confirm-before-navigating-away/web-components.html
@@ -0,0 +1,36 @@
+Open
+
+
+
+ Cancel
+ Change route
+
+
+
+
+
diff --git a/docs/src/content/examples/confirm-that-an-application-was-submitted/angular.html b/docs/src/content/examples/confirm-that-an-application-was-submitted/angular.html
new file mode 100644
index 0000000000..504944984d
--- /dev/null
+++ b/docs/src/content/examples/confirm-that-an-application-was-submitted/angular.html
@@ -0,0 +1,19 @@
+You have completed the application
+
+
+ You will receive a copy of the confirmation to the email person@email.com
+ Confirmation number: 1234ABC
+
+
+Go back to the dashboard, or direct your user somewhere else useful.
+Other information about what was just completed, other tertiary information, and/or contact information.
+
+Phone: 780 123 4567
+
+Email: information@gov.ab.ca
+
+
+
+ Go to application
+ Back to dashboard
+
diff --git a/docs/src/content/examples/confirm-that-an-application-was-submitted/angular.ts b/docs/src/content/examples/confirm-that-an-application-was-submitted/angular.ts
new file mode 100644
index 0000000000..817bed0c4c
--- /dev/null
+++ b/docs/src/content/examples/confirm-that-an-application-was-submitted/angular.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-confirm-that-an-application-was-submitted",
+ templateUrl: "./angular.html",
+})
+export class ConfirmThatAnApplicationWasSubmittedComponent {}
diff --git a/docs/src/content/examples/confirm-that-an-application-was-submitted/index.mdx b/docs/src/content/examples/confirm-that-an-application-was-submitted/index.mdx
new file mode 100644
index 0000000000..0aa182640f
--- /dev/null
+++ b/docs/src/content/examples/confirm-that-an-application-was-submitted/index.mdx
@@ -0,0 +1,36 @@
+---
+id: confirm-that-an-application-was-submitted
+title: Confirm that an application was submitted
+categories:
+ - feedback-and-alerts
+scale: page
+userType: citizen
+tags:
+ - confirmation
+ - success
+ - callout
+ - application
+components:
+ - callout
+ - button
+ - button-group
+status: published
+---
+
+Display a confirmation screen to indicate successful application submission.
+
+## When to use
+
+Use this pattern when:
+- A user has successfully completed an application or form
+- You need to confirm the submission was received
+- Users need a confirmation number for their records
+- You want to provide next steps after submission
+
+## Considerations
+
+- Use a success callout to clearly indicate success
+- Include a confirmation number users can reference later
+- Mention where a confirmation email will be sent
+- Provide clear next steps and navigation options
+- Include contact information for questions
diff --git a/docs/src/content/examples/confirm-that-an-application-was-submitted/react.tsx b/docs/src/content/examples/confirm-that-an-application-was-submitted/react.tsx
new file mode 100644
index 0000000000..48ad2511ec
--- /dev/null
+++ b/docs/src/content/examples/confirm-that-an-application-was-submitted/react.tsx
@@ -0,0 +1,28 @@
+import { GoabButton, GoabButtonGroup, GoabCallout, GoabText } from "@abgov/react-components";
+
+export function ConfirmThatAnApplicationWasSubmitted() {
+ return (
+ <>
+ You have completed the application
+
+
+ You will receive a copy of the confirmation to the email person@email.com
+ Confirmation number: 1234ABC
+
+
+ Go back to the dashboard, or direct your user somewhere else useful.
+
+ Other information about what was just completed, other tertiary information, and/or contact information.
+
+ Phone: 780 123 4567
+
+ Email: information@gov.ab.ca
+
+
+
+ Go to application
+ Back to dashboard
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/confirm-that-an-application-was-submitted/web-components.html b/docs/src/content/examples/confirm-that-an-application-was-submitted/web-components.html
new file mode 100644
index 0000000000..294db814f8
--- /dev/null
+++ b/docs/src/content/examples/confirm-that-an-application-was-submitted/web-components.html
@@ -0,0 +1,19 @@
+You have completed the application
+
+
+ You will receive a copy of the confirmation to the email person@email.com
+ Confirmation number: 1234ABC
+
+
+Go back to the dashboard, or direct your user somewhere else useful.
+Other information about what was just completed, other tertiary information, and/or contact information.
+
+Phone: 780 123 4567
+
+Email: information@gov.ab.ca
+
+
+
+ Go to application
+ Back to dashboard
+
diff --git a/docs/src/content/examples/copy-to-clipboard/angular.html b/docs/src/content/examples/copy-to-clipboard/angular.html
new file mode 100644
index 0000000000..a244c9d176
--- /dev/null
+++ b/docs/src/content/examples/copy-to-clipboard/angular.html
@@ -0,0 +1,7 @@
+
+
+ $goa-color-interactive-default
+
+
+
+
diff --git a/docs/src/content/examples/copy-to-clipboard/angular.ts b/docs/src/content/examples/copy-to-clipboard/angular.ts
new file mode 100644
index 0000000000..1ddfb90b5d
--- /dev/null
+++ b/docs/src/content/examples/copy-to-clipboard/angular.ts
@@ -0,0 +1,25 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-copy-to-clipboard",
+ templateUrl: "./angular.html",
+ styles: [`
+ .token-block {
+ background-color: var(--goa-color-interactive-default);
+ height: 22px;
+ width: 24px;
+ border-radius: var(--goa-border-radius-s);
+ }
+ `]
+})
+export class CopyToClipboardComponent {
+ isCopied = false;
+
+ copyCode(): void {
+ const codeToCopy = "$goa-color-interactive-default";
+ navigator.clipboard.writeText(codeToCopy).then(() => {
+ this.isCopied = true;
+ setTimeout(() => this.isCopied = false, 1000);
+ });
+ }
+}
diff --git a/docs/src/content/examples/copy-to-clipboard/index.mdx b/docs/src/content/examples/copy-to-clipboard/index.mdx
new file mode 100644
index 0000000000..adcee8ac42
--- /dev/null
+++ b/docs/src/content/examples/copy-to-clipboard/index.mdx
@@ -0,0 +1,35 @@
+---
+id: copy-to-clipboard
+title: Copy to clipboard
+categories:
+ - inputs-and-actions
+scale: interaction
+userType: both
+tags:
+ - clipboard
+ - copy
+ - tooltip
+ - icon-button
+components:
+ - block
+ - icon-button
+ - tooltip
+status: published
+---
+
+Allow users to quickly copy text or data to their clipboard with a single click.
+
+## When to use
+
+Use this pattern when:
+- Users need to copy values like tokens, codes, or IDs
+- Quick access to copy functionality improves workflow
+- The copied value is clearly visible alongside the copy action
+- Users benefit from instant feedback when copying
+
+## Considerations
+
+- Show visual feedback ("Copied") when the copy action succeeds
+- Use a tooltip to indicate the copy action before and after clicking
+- Position the copy button near the content being copied
+- Reset the "Copied" state after a short delay
diff --git a/docs/src/content/examples/copy-to-clipboard/react.tsx b/docs/src/content/examples/copy-to-clipboard/react.tsx
new file mode 100644
index 0000000000..1c8e207f47
--- /dev/null
+++ b/docs/src/content/examples/copy-to-clipboard/react.tsx
@@ -0,0 +1,35 @@
+import { useState } from "react";
+import { GoabBlock, GoabIconButton, GoabTooltip } from "@abgov/react-components";
+
+export function CopyToClipboard() {
+ const [isCopied, setIsCopied] = useState(false);
+
+ function copyCode() {
+ const codeToCopy = "$goa-color-interactive-default";
+ navigator.clipboard.writeText(codeToCopy).then(() => {
+ setIsCopied(true);
+ setTimeout(() => setIsCopied(false), 1000);
+ });
+ }
+
+ return (
+ <>
+
+
+
+
+ $goa-color-interactive-default
+
+
+
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/copy-to-clipboard/web-components.html b/docs/src/content/examples/copy-to-clipboard/web-components.html
new file mode 100644
index 0000000000..2fae373469
--- /dev/null
+++ b/docs/src/content/examples/copy-to-clipboard/web-components.html
@@ -0,0 +1,33 @@
+
+
+
+
+ $goa-color-interactive-default
+
+
+
+
+
+
diff --git a/docs/src/content/examples/disabled-button-with-a-required-field/angular.html b/docs/src/content/examples/disabled-button-with-a-required-field/angular.html
new file mode 100644
index 0000000000..07bc5f18d6
--- /dev/null
+++ b/docs/src/content/examples/disabled-button-with-a-required-field/angular.html
@@ -0,0 +1,20 @@
+
diff --git a/docs/src/content/examples/disabled-button-with-a-required-field/angular.ts b/docs/src/content/examples/disabled-button-with-a-required-field/angular.ts
new file mode 100644
index 0000000000..83bcac0228
--- /dev/null
+++ b/docs/src/content/examples/disabled-button-with-a-required-field/angular.ts
@@ -0,0 +1,28 @@
+import { Component } from "@angular/core";
+import { GoabInputOnChangeDetail } from "@abgov/ui-components-common";
+
+@Component({
+ selector: "app-disabled-button-with-required-field",
+ templateUrl: "./angular.html"
+})
+export class DisabledButtonWithRequiredFieldComponent {
+ inputValue = "";
+
+ onInputChange(detail: GoabInputOnChangeDetail): void {
+ this.inputValue = detail.value;
+ }
+
+ onConfirm(): void {
+ // Handle form submission
+ console.log("Form submitted with:", this.inputValue);
+ }
+
+ onCancel(): void {
+ // Handle cancellation
+ this.inputValue = "";
+ }
+
+ get isDisabled(): boolean {
+ return this.inputValue.trim() === "";
+ }
+}
diff --git a/docs/src/content/examples/disabled-button-with-a-required-field/index.mdx b/docs/src/content/examples/disabled-button-with-a-required-field/index.mdx
new file mode 100644
index 0000000000..754e65a308
--- /dev/null
+++ b/docs/src/content/examples/disabled-button-with-a-required-field/index.mdx
@@ -0,0 +1,36 @@
+---
+id: disabled-button-with-a-required-field
+title: Disabled button with a required field
+categories:
+ - inputs-and-actions
+scale: interaction
+userType: both
+tags:
+ - button
+ - form
+ - validation
+ - disabled
+ - required
+components:
+ - button
+ - button-group
+ - form-item
+ - input
+status: published
+---
+
+Disable a submit button until required form fields are completed.
+
+## When to use
+
+Use this pattern when:
+- A form has required fields that must be filled before submission
+- You want to provide visual feedback that the form is incomplete
+- Preventing invalid form submissions is important
+
+## Considerations
+
+- Ensure the disabled state is visually distinct and accessible
+- Consider showing validation messages when users try to interact with disabled buttons
+- Use the `requirement="required"` prop on form items to indicate mandatory fields
+- Enable the button as soon as all required fields have valid values
diff --git a/docs/src/content/examples/disabled-button-with-a-required-field/react.tsx b/docs/src/content/examples/disabled-button-with-a-required-field/react.tsx
new file mode 100644
index 0000000000..4a6bbfc93c
--- /dev/null
+++ b/docs/src/content/examples/disabled-button-with-a-required-field/react.tsx
@@ -0,0 +1,49 @@
+import { useState } from "react";
+import {
+ GoabButton,
+ GoabButtonGroup,
+ GoabFormItem,
+ GoabInput
+} from "@abgov/react-components";
+import { GoabInputOnChangeDetail } from "@abgov/ui-components-common";
+
+export function DisabledButtonWithARequiredField() {
+ const [inputValue, setInputValue] = useState("");
+
+ const handleInputChange = (detail: GoabInputOnChangeDetail) => {
+ setInputValue(detail.value);
+ };
+
+ const handleConfirm = () => {
+ // Handle form submission
+ console.log("Form submitted with:", inputValue);
+ };
+
+ const handleCancel = () => {
+ // Handle cancellation
+ setInputValue("");
+ };
+
+ return (
+
+ );
+}
diff --git a/docs/src/content/examples/disabled-button-with-a-required-field/web-components.html b/docs/src/content/examples/disabled-button-with-a-required-field/web-components.html
new file mode 100644
index 0000000000..d879acff1d
--- /dev/null
+++ b/docs/src/content/examples/disabled-button-with-a-required-field/web-components.html
@@ -0,0 +1,34 @@
+
+
+
diff --git a/docs/src/content/examples/display-numbers-in-a-table-so-they-can-be-scanned-easily/angular.html b/docs/src/content/examples/display-numbers-in-a-table-so-they-can-be-scanned-easily/angular.html
new file mode 100644
index 0000000000..602e712ac4
--- /dev/null
+++ b/docs/src/content/examples/display-numbers-in-a-table-so-they-can-be-scanned-easily/angular.html
@@ -0,0 +1,36 @@
+
+
+
+
First name
+
Last name
+
ID Number
+
+
+
+
+
Sarah
+
Johnson
+
54
+
+
+
Michael
+
Chen
+
4567
+
+
+
Emily
+
Williams
+
892
+
+
+
David
+
Brown
+
12345
+
+
+
Jennifer
+
Martinez
+
7
+
+
+
diff --git a/docs/src/content/examples/display-numbers-in-a-table-so-they-can-be-scanned-easily/angular.ts b/docs/src/content/examples/display-numbers-in-a-table-so-they-can-be-scanned-easily/angular.ts
new file mode 100644
index 0000000000..4b167d0d7b
--- /dev/null
+++ b/docs/src/content/examples/display-numbers-in-a-table-so-they-can-be-scanned-easily/angular.ts
@@ -0,0 +1,9 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-display-numbers-in-table",
+ templateUrl: "./angular.html"
+})
+export class DisplayNumbersInTableComponent {
+ // No logic required for this static example
+}
diff --git a/docs/src/content/examples/display-numbers-in-a-table-so-they-can-be-scanned-easily/index.mdx b/docs/src/content/examples/display-numbers-in-a-table-so-they-can-be-scanned-easily/index.mdx
new file mode 100644
index 0000000000..3016e29eba
--- /dev/null
+++ b/docs/src/content/examples/display-numbers-in-a-table-so-they-can-be-scanned-easily/index.mdx
@@ -0,0 +1,33 @@
+---
+id: display-numbers-in-a-table-so-they-can-be-scanned-easily
+title: Display numbers in a table so they can be scanned easily
+categories:
+ - content-layout
+scale: task
+userType: worker
+tags:
+ - table
+ - numbers
+ - data
+ - alignment
+ - scanning
+components:
+ - table
+status: published
+---
+
+Right-align numeric columns in tables to make them easier to scan and compare.
+
+## When to use
+
+Use this pattern when:
+- Displaying numeric data in table columns (IDs, amounts, counts)
+- Users need to quickly scan and compare values
+- The table contains a mix of text and numeric data
+
+## Considerations
+
+- Use the `goa-table-number-header` class on `
` elements for numeric column headers
+- Use the `goa-table-number-column` class on `
` elements for numeric data cells
+- Right-alignment helps users visually compare magnitudes of numbers
+- Consider consistent decimal formatting for financial data
diff --git a/docs/src/content/examples/display-numbers-in-a-table-so-they-can-be-scanned-easily/react.tsx b/docs/src/content/examples/display-numbers-in-a-table-so-they-can-be-scanned-easily/react.tsx
new file mode 100644
index 0000000000..4f41b5738e
--- /dev/null
+++ b/docs/src/content/examples/display-numbers-in-a-table-so-they-can-be-scanned-easily/react.tsx
@@ -0,0 +1,42 @@
+import { GoabTable } from "@abgov/react-components";
+
+export function DisplayNumbersInATableSoTheyCanBeScannedEasily() {
+ return (
+
+
+
diff --git a/docs/src/content/examples/dynamically-change-items-in-a-dropdown-list/angular.ts b/docs/src/content/examples/dynamically-change-items-in-a-dropdown-list/angular.ts
new file mode 100644
index 0000000000..2b8d528ca0
--- /dev/null
+++ b/docs/src/content/examples/dynamically-change-items-in-a-dropdown-list/angular.ts
@@ -0,0 +1,36 @@
+import { Component, OnInit } from "@angular/core";
+import { FormControl, FormGroup } from "@angular/forms";
+
+@Component({
+ selector: "app-dynamically-change-dropdown-items",
+ templateUrl: "./angular.html"
+})
+export class DynamicallyChangeDropdownItemsComponent implements OnInit {
+ changeForm = new FormGroup({
+ parentDropdown: new FormControl(""),
+ childDropdown: new FormControl(""),
+ });
+
+ parents = ["All", "Big", "Small"];
+ children: string[] = [];
+
+ childrenAll = ["Bus", "Elephant", "Key", "Pen", "Watch", "Truck"];
+ childrenBig = ["Elephant", "Truck", "Bus"];
+ childrenSmall = ["Key", "Pen", "Watch"];
+
+ ngOnInit(): void {
+ this.onChange();
+ }
+
+ onChange(): void {
+ this.changeForm.get("parentDropdown")?.valueChanges.subscribe((value) => {
+ if (value === "All") this.children = this.childrenAll;
+ else if (value === "Big") this.children = this.childrenBig;
+ else this.children = this.childrenSmall;
+ });
+ }
+
+ generateUniqueKey(index: number, item: string): string {
+ return `${item}_${index}_${Math.random()}`;
+ }
+}
diff --git a/docs/src/content/examples/dynamically-change-items-in-a-dropdown-list/index.mdx b/docs/src/content/examples/dynamically-change-items-in-a-dropdown-list/index.mdx
new file mode 100644
index 0000000000..e1f1b9f061
--- /dev/null
+++ b/docs/src/content/examples/dynamically-change-items-in-a-dropdown-list/index.mdx
@@ -0,0 +1,35 @@
+---
+id: dynamically-change-items-in-a-dropdown-list
+title: Dynamically change items in a dropdown list
+categories:
+ - inputs-and-actions
+scale: interaction
+userType: both
+tags:
+ - dropdown
+ - dynamic
+ - cascading
+ - dependent
+ - form
+components:
+ - dropdown
+ - dropdown-item
+ - form-item
+status: published
+---
+
+Update dropdown options based on the selection in another dropdown (cascading/dependent dropdowns).
+
+## When to use
+
+Use this pattern when:
+- Options in one dropdown depend on the selection in another
+- You need to filter available choices based on a category
+- Building hierarchical selection interfaces (e.g., country/state/city)
+
+## Considerations
+
+- Use `mountType="reset"` to clear and repopulate dropdown items
+- Generate unique keys for items to ensure proper re-rendering
+- Provide placeholder text to guide users when no selection is made
+- Consider loading states if data fetching is required
diff --git a/docs/src/content/examples/dynamically-change-items-in-a-dropdown-list/react.tsx b/docs/src/content/examples/dynamically-change-items-in-a-dropdown-list/react.tsx
new file mode 100644
index 0000000000..359e9c83fd
--- /dev/null
+++ b/docs/src/content/examples/dynamically-change-items-in-a-dropdown-list/react.tsx
@@ -0,0 +1,58 @@
+import { useState } from "react";
+import {
+ GoabDropdown,
+ GoabDropdownItem,
+ GoabFormItem,
+} from "@abgov/react-components";
+import { GoabDropdownOnChangeDetail } from "@abgov/ui-components-common";
+
+export function DynamicallyChangeItemsInADropdownList() {
+ const [children, setChildren] = useState([]);
+ const parents = ["All", "Big", "Small"];
+ const childrenAll = ["Bus", "Elephant", "Key", "Pen", "Watch", "Truck"];
+ const childrenBig = ["Elephant", "Truck", "Bus"];
+ const childrenSmall = ["Key", "Pen", "Watch"];
+
+ const loadItems = (value: string) => {
+ if (value === "All") setChildren(childrenAll);
+ else if (value === "Big") setChildren(childrenBig);
+ else setChildren(childrenSmall);
+ };
+
+ const logSelection = () => {
+ console.log("Item selected");
+ };
+
+ return (
+ <>
+
+
+ loadItems(event.value as string)
+ }>
+ {parents.map(parent => (
+
+ ))}
+
+
+
+
+
+ {children.map((child) => (
+
+ ))}
+
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/dynamically-change-items-in-a-dropdown-list/web-components.html b/docs/src/content/examples/dynamically-change-items-in-a-dropdown-list/web-components.html
new file mode 100644
index 0000000000..1e7ddc26b9
--- /dev/null
+++ b/docs/src/content/examples/dynamically-change-items-in-a-dropdown-list/web-components.html
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/examples/expand-or-collapse-part-of-a-form/angular.html b/docs/src/content/examples/expand-or-collapse-part-of-a-form/angular.html
new file mode 100644
index 0000000000..68fbd5713e
--- /dev/null
+++ b/docs/src/content/examples/expand-or-collapse-part-of-a-form/angular.html
@@ -0,0 +1,26 @@
+Review your application
+
+
+
+
+
+
+
Date of referral
+
January 27, 2021
+
Work safety concerns
+
None
+
Type of referral
+
Word of mouth, internet search
+
Intake received from another site
+
Yes
+
+
+
+
+
+
Name
+
Joan Smith
+
Contact preference
+
Text message
+
+
diff --git a/docs/src/content/examples/expand-or-collapse-part-of-a-form/angular.ts b/docs/src/content/examples/expand-or-collapse-part-of-a-form/angular.ts
new file mode 100644
index 0000000000..fd450d9534
--- /dev/null
+++ b/docs/src/content/examples/expand-or-collapse-part-of-a-form/angular.ts
@@ -0,0 +1,26 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-expand-collapse-form",
+ templateUrl: "./angular.html",
+ styles: [`
+ dl.accordion-example {
+ margin: 0 0;
+ }
+ .accordion-example dt {
+ color: var(--goa-color-text-default);
+ font: var(--goa-typography-heading-s);
+ margin-bottom: var(--goa-space-xs);
+ }
+ .accordion-example dd {
+ margin: 0 0 var(--goa-space-l);
+ font: var(--goa-typography-body-m);
+ }
+ .accordion-example dd:last-of-type {
+ margin-bottom: 0;
+ }
+ `]
+})
+export class ExpandCollapseFormComponent {
+ // No logic required for this static example
+}
diff --git a/docs/src/content/examples/expand-or-collapse-part-of-a-form/index.mdx b/docs/src/content/examples/expand-or-collapse-part-of-a-form/index.mdx
new file mode 100644
index 0000000000..8f66c339d7
--- /dev/null
+++ b/docs/src/content/examples/expand-or-collapse-part-of-a-form/index.mdx
@@ -0,0 +1,35 @@
+---
+id: expand-or-collapse-part-of-a-form
+title: Expand or collapse part of a form
+categories:
+ - forms
+scale: task
+userType: both
+tags:
+ - accordion
+ - form
+ - review
+ - collapsible
+ - badge
+components:
+ - accordion
+ - badge
+status: published
+---
+
+Use accordions to organize form review sections that users can expand or collapse.
+
+## When to use
+
+Use this pattern when:
+- Presenting a review summary of form sections before submission
+- Users need to verify information across multiple categories
+- Sections contain detailed information that may not need constant visibility
+- You want to highlight sections that have been updated
+
+## Considerations
+
+- Use `headingContent` to add badges or status indicators to section headers
+- Use definition lists (`
`) for structured label/value pairs
+- Apply consistent spacing with CSS custom properties
+- Consider defaulting important or recently updated sections to expanded state
diff --git a/docs/src/content/examples/expand-or-collapse-part-of-a-form/react.tsx b/docs/src/content/examples/expand-or-collapse-part-of-a-form/react.tsx
new file mode 100644
index 0000000000..2a6301ec96
--- /dev/null
+++ b/docs/src/content/examples/expand-or-collapse-part-of-a-form/react.tsx
@@ -0,0 +1,51 @@
+import { GoabAccordion, GoabBadge, GoabText } from "@abgov/react-components";
+
+export function ExpandOrCollapsePartOfAForm() {
+ return (
+ <>
+
+
+ Review your application
+
+ }>
+
+
+
diff --git a/docs/src/content/examples/give-background-information-before-asking-a-question/angular.html b/docs/src/content/examples/give-background-information-before-asking-a-question/angular.html
new file mode 100644
index 0000000000..b48f14adca
--- /dev/null
+++ b/docs/src/content/examples/give-background-information-before-asking-a-question/angular.html
@@ -0,0 +1,33 @@
+
+ Back
+
+
+Current school status
+
+ School can encompass foundational programs that help individuals gain basic skills for
+ further learning and living, such as literacy and numeracy courses. It also includes
+ skills and employment training programs, designed to equip you with specific skills for
+ the job market.
+
+
+ Post-secondary education, such as Bachelor's, Master's, or Doctoral degrees, and
+ continuing education courses for professional or personal development, are also
+ categorized under 'school'.
+
+
+ Contact your provider if you're concerned about your school status.
+
+
+
+
+
+
+
+
+
+
+ Save and continue
+
diff --git a/docs/src/content/examples/give-background-information-before-asking-a-question/angular.ts b/docs/src/content/examples/give-background-information-before-asking-a-question/angular.ts
new file mode 100644
index 0000000000..0688033bf3
--- /dev/null
+++ b/docs/src/content/examples/give-background-information-before-asking-a-question/angular.ts
@@ -0,0 +1,41 @@
+import { Component } from "@angular/core";
+import { GoabRadioGroupOnChangeDetail } from "@abgov/ui-components-common";
+
+@Component({
+ selector: "app-give-background-info",
+ templateUrl: "./angular.html",
+ styles: [`
+ h2.section-title {
+ margin-bottom: var(--goa-space-l);
+ }
+ a.back-link::before {
+ content: "";
+ display: inline-block;
+ width: 42px;
+ height: 24px;
+ vertical-align: middle;
+ background: url('data:image/svg+xml,') center center no-repeat;
+ }
+ a.back-link:visited::before,
+ a.back-link:hover::before {
+ background: url('data:image/svg+xml,') center center no-repeat;
+ }
+ a.back-link {
+ margin-top: var(--goa-space-m);
+ }
+ :host a.back-link + h2 {
+ margin-top: var(--goa-space-2xl);
+ }
+ `]
+})
+export class GiveBackgroundInfoComponent {
+ selectedValue = "";
+
+ onChange(event: GoabRadioGroupOnChangeDetail): void {
+ this.selectedValue = event.value as string;
+ }
+
+ onSubmit(): void {
+ console.log("Selected:", this.selectedValue);
+ }
+}
diff --git a/docs/src/content/examples/give-background-information-before-asking-a-question/index.mdx b/docs/src/content/examples/give-background-information-before-asking-a-question/index.mdx
new file mode 100644
index 0000000000..8b4038b2b5
--- /dev/null
+++ b/docs/src/content/examples/give-background-information-before-asking-a-question/index.mdx
@@ -0,0 +1,38 @@
+---
+id: give-background-information-before-asking-a-question
+title: Give background information before asking a question
+categories:
+ - forms
+scale: task
+userType: citizen
+tags:
+ - form
+ - question
+ - context
+ - radio
+ - citizen-facing
+components:
+ - form-item
+ - radio-group
+ - radio-item
+ - button
+status: published
+---
+
+Provide explanatory context before asking a question to help users understand what is being asked.
+
+## When to use
+
+Use this pattern when:
+- The question requires domain knowledge to answer correctly
+- Terms need clarification for users unfamiliar with the subject
+- Providing context will reduce confusion and incorrect answers
+- Building citizen-facing forms where accessibility of information is important
+
+## Considerations
+
+- Place context information before the question, not after
+- Use clear, plain language that citizens can understand
+- Suggest where users can get additional help if needed
+- Keep explanatory text focused and relevant to the question
+- Use appropriate heading hierarchy for screen reader accessibility
diff --git a/docs/src/content/examples/give-background-information-before-asking-a-question/react.tsx b/docs/src/content/examples/give-background-information-before-asking-a-question/react.tsx
new file mode 100644
index 0000000000..6eb0cf69f4
--- /dev/null
+++ b/docs/src/content/examples/give-background-information-before-asking-a-question/react.tsx
@@ -0,0 +1,60 @@
+import {
+ GoabButton,
+ GoabFormItem,
+ GoabLink,
+ GoabRadioGroup,
+ GoabRadioItem,
+ GoabText
+} from "@abgov/react-components";
+import { GoabRadioGroupOnChangeDetail } from "@abgov/ui-components-common";
+import { useState } from "react";
+
+export function GiveBackgroundInformationBeforeAskingAQuestion() {
+ const [selectedValue, setSelectedValue] = useState("");
+
+ const handleChange = (event: GoabRadioGroupOnChangeDetail) => {
+ setSelectedValue(event.value as string);
+ };
+
+ const handleSubmit = () => {
+ console.log("Selected:", selectedValue);
+ };
+
+ return (
+ <>
+
+ Back
+
+
+ Current school status
+
+ School can encompass foundational programs that help individuals gain basic skills for
+ further learning and living, such as literacy and numeracy courses. It also includes
+ skills and employment training programs, designed to equip you with specific skills for
+ the job market.
+
+
+ Post-secondary education, such as Bachelor's, Master's, or Doctoral degrees, and
+ continuing education courses for professional or personal development, are also
+ categorized under 'school'.
+
+
+ Contact your provider if you're concerned about your school status.
+
+
+
+
+
+
+
+
+
+
+ Save and continue
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/give-background-information-before-asking-a-question/web-components.html b/docs/src/content/examples/give-background-information-before-asking-a-question/web-components.html
new file mode 100644
index 0000000000..00037bd5a4
--- /dev/null
+++ b/docs/src/content/examples/give-background-information-before-asking-a-question/web-components.html
@@ -0,0 +1,44 @@
+
+ Back
+
+
+Current school status
+
+ School can encompass foundational programs that help individuals gain basic skills for
+ further learning and living, such as literacy and numeracy courses. It also includes
+ skills and employment training programs, designed to equip you with specific skills for
+ the job market.
+
+
+ Post-secondary education, such as Bachelor's, Master's, or Doctoral degrees, and
+ continuing education courses for professional or personal development, are also
+ categorized under 'school'.
+
+
+ Contact your provider if you're concerned about your school status.
+
+
+
+
+
+
+
+
+
+
+ Save and continue
+
+
+
diff --git a/docs/src/content/examples/give-context-before-asking-a-long-answer-question/angular.html b/docs/src/content/examples/give-context-before-asking-a-long-answer-question/angular.html
new file mode 100644
index 0000000000..9d83d1d25b
--- /dev/null
+++ b/docs/src/content/examples/give-context-before-asking-a-long-answer-question/angular.html
@@ -0,0 +1,35 @@
+
+ Back
+
+
+Submit a question about your benefits
+
+ If you need clarification about your benefit eligibility, payment schedule, or application status, submit your
+ question here.
+
+
+
+
+
+
+ Include your benefit program name, mention any recent correspondence you received and/or provide any
+ relevant case or reference numbers.
+
+
+
+
+
+ Continue
+
+
diff --git a/docs/src/content/examples/give-context-before-asking-a-long-answer-question/angular.ts b/docs/src/content/examples/give-context-before-asking-a-long-answer-question/angular.ts
new file mode 100644
index 0000000000..5ae3e82da9
--- /dev/null
+++ b/docs/src/content/examples/give-context-before-asking-a-long-answer-question/angular.ts
@@ -0,0 +1,20 @@
+import { Component } from "@angular/core";
+import { FormBuilder, FormGroup } from "@angular/forms";
+
+@Component({
+ selector: "app-give-context-long-answer",
+ templateUrl: "./angular.html"
+})
+export class GiveContextLongAnswerComponent {
+ form: FormGroup;
+
+ constructor(private fb: FormBuilder) {
+ this.form = this.fb.group({
+ program: [""]
+ });
+ }
+
+ onContinue(): void {
+ console.log("Submitted:", this.form.get("program")?.value);
+ }
+}
diff --git a/docs/src/content/examples/give-context-before-asking-a-long-answer-question/index.mdx b/docs/src/content/examples/give-context-before-asking-a-long-answer-question/index.mdx
new file mode 100644
index 0000000000..cbfc65cb25
--- /dev/null
+++ b/docs/src/content/examples/give-context-before-asking-a-long-answer-question/index.mdx
@@ -0,0 +1,39 @@
+---
+id: give-context-before-asking-a-long-answer-question
+title: Give context before asking a long answer question
+categories:
+ - forms
+scale: task
+userType: citizen
+tags:
+ - form
+ - text-area
+ - question
+ - context
+ - details
+ - citizen-facing
+components:
+ - text-area
+ - form-item
+ - details
+ - button
+ - button-group
+status: published
+---
+
+Provide context and guidance before a long-answer text field to help users provide relevant information.
+
+## When to use
+
+Use this pattern when:
+- Asking open-ended questions that require detailed responses
+- Users may not know what information is most helpful to provide
+- You want to encourage more useful and complete answers
+- Building citizen-facing forms with benefit inquiries or support requests
+
+## Considerations
+
+- Explain the purpose of the question briefly
+- Use a Details component to provide additional guidance without cluttering the form
+- Set appropriate character limits with `maxCount` and `countBy` props
+- Keep instructions focused on what will help process their request
diff --git a/docs/src/content/examples/give-context-before-asking-a-long-answer-question/react.tsx b/docs/src/content/examples/give-context-before-asking-a-long-answer-question/react.tsx
new file mode 100644
index 0000000000..127bbf1ae7
--- /dev/null
+++ b/docs/src/content/examples/give-context-before-asking-a-long-answer-question/react.tsx
@@ -0,0 +1,64 @@
+import { useState } from "react";
+import {
+ GoabButton,
+ GoabButtonGroup,
+ GoabDetails,
+ GoabFormItem,
+ GoabLink,
+ GoabText,
+ GoabTextarea
+} from "@abgov/react-components";
+import { GoabTextareaOnChangeDetail } from "@abgov/ui-components-common";
+
+export function GiveContextBeforeAskingALongAnswerQuestion() {
+ const [textValue, setTextValue] = useState("");
+
+ const handleChange = (event: GoabTextareaOnChangeDetail) => {
+ setTextValue(event.value);
+ };
+
+ const handleContinue = () => {
+ console.log("Submitted:", textValue);
+ };
+
+ return (
+ <>
+
+ Back
+
+
+ Submit a question about your benefits
+
+ If you need clarification about your benefit eligibility, payment schedule, or application status, submit your
+ question here.
+
+
+
+
+
+
+ Include your benefit program name, mention any recent correspondence you received and/or provide any
+ relevant case or reference numbers.
+
+
+
+
+
+ Continue
+
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/give-context-before-asking-a-long-answer-question/web-components.html b/docs/src/content/examples/give-context-before-asking-a-long-answer-question/web-components.html
new file mode 100644
index 0000000000..d850f7159b
--- /dev/null
+++ b/docs/src/content/examples/give-context-before-asking-a-long-answer-question/web-components.html
@@ -0,0 +1,44 @@
+
+ Back
+
+
+Submit a question about your benefits
+
+ If you need clarification about your benefit eligibility, payment schedule, or application status, submit your
+ question here.
+
+
+
+
+
+
+ Include your benefit program name, mention any recent correspondence you received and/or provide any
+ relevant case or reference numbers.
+
+
+
+
+
+ Continue
+
+
+
+
diff --git a/docs/src/content/examples/group-related-questions-together-on-a-question-page/angular.html b/docs/src/content/examples/group-related-questions-together-on-a-question-page/angular.html
new file mode 100644
index 0000000000..1c83e3b61c
--- /dev/null
+++ b/docs/src/content/examples/group-related-questions-together-on-a-question-page/angular.html
@@ -0,0 +1,71 @@
+
+ Back
+
+
+Your address
+This is the home address of the person applying
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Save and continue
+
diff --git a/docs/src/content/examples/group-related-questions-together-on-a-question-page/angular.ts b/docs/src/content/examples/group-related-questions-together-on-a-question-page/angular.ts
new file mode 100644
index 0000000000..72e95b314f
--- /dev/null
+++ b/docs/src/content/examples/group-related-questions-together-on-a-question-page/angular.ts
@@ -0,0 +1,37 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-group-related-questions",
+ templateUrl: "./angular.html",
+})
+export class GroupRelatedQuestionsComponent {
+ addressLine1 = "";
+ addressLine2 = "";
+ townCity = "";
+ province = "";
+ postalCode = "";
+
+ onAddressLine1Change(value: string): void {
+ this.addressLine1 = value;
+ }
+
+ onAddressLine2Change(value: string): void {
+ this.addressLine2 = value;
+ }
+
+ onTownCityChange(value: string): void {
+ this.townCity = value;
+ }
+
+ onProvinceChange(value: string): void {
+ this.province = value;
+ }
+
+ onPostalCodeChange(value: string): void {
+ this.postalCode = value;
+ }
+
+ onSubmit(): void {
+ console.log("Form submitted");
+ }
+}
diff --git a/docs/src/content/examples/group-related-questions-together-on-a-question-page/index.mdx b/docs/src/content/examples/group-related-questions-together-on-a-question-page/index.mdx
new file mode 100644
index 0000000000..d885273699
--- /dev/null
+++ b/docs/src/content/examples/group-related-questions-together-on-a-question-page/index.mdx
@@ -0,0 +1,36 @@
+---
+id: group-related-questions-together-on-a-question-page
+title: Group related questions together on a question page
+categories:
+ - forms
+scale: page
+userType: citizen
+tags:
+ - forms
+ - address
+ - question-page
+components:
+ - form-item
+ - input
+ - dropdown
+ - dropdown-item
+ - button
+status: published
+---
+
+Group related form fields together on a single page to collect address information from users, making it easier to complete logically connected questions at once.
+
+## When to use
+
+Use this pattern when:
+- Collecting address or contact information
+- Form fields are logically related and should be completed together
+- Users need context between related fields
+- Following a question page pattern in a multi-step form
+
+## Considerations
+
+- Use clear, descriptive labels for each form field
+- Include a back link for navigation in multi-step forms
+- Consider adding a section title and subtitle to provide context
+- Use appropriate input widths based on expected content length
diff --git a/docs/src/content/examples/group-related-questions-together-on-a-question-page/react.tsx b/docs/src/content/examples/group-related-questions-together-on-a-question-page/react.tsx
new file mode 100644
index 0000000000..fa6236898f
--- /dev/null
+++ b/docs/src/content/examples/group-related-questions-together-on-a-question-page/react.tsx
@@ -0,0 +1,95 @@
+import { useState } from "react";
+import {
+ GoabButton,
+ GoabDropdown,
+ GoabDropdownItem,
+ GoabFormItem,
+ GoabInput,
+ GoabLink,
+ GoabText,
+} from "@abgov/react-components";
+
+export function GroupRelatedQuestionsTogetherOnAQuestionPage() {
+ const [addressLine1, setAddressLine1] = useState("");
+ const [addressLine2, setAddressLine2] = useState("");
+ const [townCity, setTownCity] = useState("");
+ const [province, setProvince] = useState("");
+ const [postalCode, setPostalCode] = useState("");
+
+ return (
+ <>
+
+ Back
+
+
+ Your address
+ This is the home address of the person applying
+
+
+ setAddressLine1(event.value)}
+ value={addressLine1}
+ name="address-line-1"
+ ariaLabel="Address line 1"
+ width="100%"
+ />
+
+
+
+ setAddressLine2(event.value)}
+ value={addressLine2}
+ name="address-line-2"
+ ariaLabel="Address line 2"
+ width="100%"
+ />
+
+
+
+ setTownCity(event.value)}
+ value={townCity}
+ name="town-city"
+ ariaLabel="Town or city name"
+ width="460px"
+ />
+
+
+
+ setProvince(event.value ?? "")}
+ value={province}
+ name="province-territory"
+ ariaLabelledBy="provinceLabel"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ setPostalCode(event.value)}
+ value={postalCode}
+ name="postal-code"
+ width="105px"
+ />
+
+
+
+ Save and continue
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/group-related-questions-together-on-a-question-page/web-components.html b/docs/src/content/examples/group-related-questions-together-on-a-question-page/web-components.html
new file mode 100644
index 0000000000..6ae41d8638
--- /dev/null
+++ b/docs/src/content/examples/group-related-questions-together-on-a-question-page/web-components.html
@@ -0,0 +1,80 @@
+
+ Back
+
+
+Your address
+This is the home address of the person applying
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Save and continue
+
+
+
diff --git a/docs/src/content/examples/header-with-menu-click-event/angular.html b/docs/src/content/examples/header-with-menu-click-event/angular.html
new file mode 100644
index 0000000000..e105520fa5
--- /dev/null
+++ b/docs/src/content/examples/header-with-menu-click-event/angular.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+ Cases
+ Payments
+ Outstanding
+
+ Support
+ Sign in
+
diff --git a/docs/src/content/examples/header-with-menu-click-event/angular.ts b/docs/src/content/examples/header-with-menu-click-event/angular.ts
new file mode 100644
index 0000000000..9baafe29a4
--- /dev/null
+++ b/docs/src/content/examples/header-with-menu-click-event/angular.ts
@@ -0,0 +1,18 @@
+import { Component } from "@angular/core";
+import { GoabRadioGroupOnChangeDetail } from "@abgov/ui-components-common";
+
+@Component({
+ selector: "app-header-with-menu-click-event",
+ templateUrl: "./angular.html",
+})
+export class HeaderWithMenuClickEventComponent {
+ deviceWidth = "5000";
+
+ changeDeviceWidth(event: GoabRadioGroupOnChangeDetail): void {
+ this.deviceWidth = event.value;
+ }
+
+ handleMenuClick(): void {
+ alert("Menu not being displayed and you can do anything");
+ }
+}
diff --git a/docs/src/content/examples/header-with-menu-click-event/index.mdx b/docs/src/content/examples/header-with-menu-click-event/index.mdx
new file mode 100644
index 0000000000..23aed94d0d
--- /dev/null
+++ b/docs/src/content/examples/header-with-menu-click-event/index.mdx
@@ -0,0 +1,36 @@
+---
+id: header-with-menu-click-event
+title: Header with menu click event
+categories:
+ - structure-and-navigation
+scale: interaction
+userType: both
+tags:
+ - header
+ - navigation
+ - mobile
+ - menu
+components:
+ - app-header
+ - app-header-menu
+ - radio-group
+ - radio-item
+status: published
+---
+
+Handle custom menu click behavior in the app header, allowing you to intercept the mobile menu button click and implement custom functionality like custom navigation drawers.
+
+## When to use
+
+Use this pattern when:
+- You need custom behavior when the mobile menu button is clicked
+- Building a custom navigation drawer or sidebar
+- The standard header menu behavior needs to be overridden
+- You want to control menu visibility programmatically
+
+## Considerations
+
+- Use the `fullMenuBreakpoint` prop to control when the hamburger menu appears
+- The `onMenuClick` handler fires when the menu button is clicked
+- Consider accessibility when implementing custom menu behavior
+- Test across different device widths to ensure proper behavior
diff --git a/docs/src/content/examples/header-with-menu-click-event/react.tsx b/docs/src/content/examples/header-with-menu-click-event/react.tsx
new file mode 100644
index 0000000000..0e868b4dd8
--- /dev/null
+++ b/docs/src/content/examples/header-with-menu-click-event/react.tsx
@@ -0,0 +1,48 @@
+import { useState } from "react";
+import {
+ GoabAppHeader,
+ GoabAppHeaderMenu,
+ GoabRadioGroup,
+ GoabRadioItem,
+} from "@abgov/react-components";
+import { GoabRadioGroupOnChangeDetail } from "@abgov/ui-components-common";
+
+export function HeaderWithMenuClickEvent() {
+ const [deviceWidth, setDeviceWidth] = useState("5000");
+
+ function handleMenuClick() {
+ alert("Menu not being displayed and you can do anything");
+ }
+
+ return (
+ <>
+
+ setDeviceWidth(event.value)
+ }
+ >
+
+
+
+
+
+
+ Cases
+ Payments
+ Outstanding
+
+ Support
+
+ Sign in
+
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/header-with-menu-click-event/web-components.html b/docs/src/content/examples/header-with-menu-click-event/web-components.html
new file mode 100644
index 0000000000..0ca26271ea
--- /dev/null
+++ b/docs/src/content/examples/header-with-menu-click-event/web-components.html
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+ Cases
+ Payments
+ Outstanding
+
+ Support
+ Sign in
+
+
+
diff --git a/docs/src/content/examples/header-with-navigation/angular.html b/docs/src/content/examples/header-with-navigation/angular.html
new file mode 100644
index 0000000000..54b8270b47
--- /dev/null
+++ b/docs/src/content/examples/header-with-navigation/angular.html
@@ -0,0 +1,10 @@
+
+
+
+ Cases
+ Payments
+ Outstanding
+
+ Support
+ Sign in
+
diff --git a/docs/src/content/examples/header-with-navigation/angular.ts b/docs/src/content/examples/header-with-navigation/angular.ts
new file mode 100644
index 0000000000..de608e0630
--- /dev/null
+++ b/docs/src/content/examples/header-with-navigation/angular.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-header-with-navigation",
+ templateUrl: "./angular.html",
+})
+export class HeaderWithNavigationComponent {}
diff --git a/docs/src/content/examples/header-with-navigation/index.mdx b/docs/src/content/examples/header-with-navigation/index.mdx
new file mode 100644
index 0000000000..20666956fc
--- /dev/null
+++ b/docs/src/content/examples/header-with-navigation/index.mdx
@@ -0,0 +1,34 @@
+---
+id: header-with-navigation
+title: Header with navigation
+categories:
+ - structure-and-navigation
+scale: task
+userType: both
+tags:
+ - header
+ - navigation
+ - menu
+components:
+ - app-header
+ - app-header-menu
+ - microsite-header
+status: published
+---
+
+Implement a standard application header with navigation menus, search functionality, and sign-in links for government services.
+
+## When to use
+
+Use this pattern when:
+- Building a government service application
+- You need consistent navigation across pages
+- Users need access to search, support, and authentication
+- Following the GoA header pattern
+
+## Considerations
+
+- Use the microsite header above the app header for government branding
+- Group related navigation items under dropdown menus
+- Include a sign-in link with the "interactive" class for proper styling
+- Consider mobile responsiveness for navigation items
diff --git a/docs/src/content/examples/header-with-navigation/react.tsx b/docs/src/content/examples/header-with-navigation/react.tsx
new file mode 100644
index 0000000000..00fe072733
--- /dev/null
+++ b/docs/src/content/examples/header-with-navigation/react.tsx
@@ -0,0 +1,17 @@
+import { GoabAppHeader, GoabAppHeaderMenu } from "@abgov/react-components";
+
+export function HeaderWithNavigation() {
+ return (
+
+
+ Cases
+ Payments
+ Outstanding
+
+ Support
+
+ Sign in
+
+
+ );
+}
diff --git a/docs/src/content/examples/header-with-navigation/web-components.html b/docs/src/content/examples/header-with-navigation/web-components.html
new file mode 100644
index 0000000000..6d8461ede4
--- /dev/null
+++ b/docs/src/content/examples/header-with-navigation/web-components.html
@@ -0,0 +1,10 @@
+
+
+
+ Cases
+ Payments
+ Outstanding
+
+ Support
+ Sign in
+
diff --git a/docs/src/content/examples/hero-banner-with-actions/angular.html b/docs/src/content/examples/hero-banner-with-actions/angular.html
new file mode 100644
index 0000000000..8e1bc0ec5b
--- /dev/null
+++ b/docs/src/content/examples/hero-banner-with-actions/angular.html
@@ -0,0 +1,6 @@
+
+ Resources are available to help Alberta entrepreneurs and small businesses start, grow and succeed.
+
+ Call to action
+
+
diff --git a/docs/src/content/examples/hero-banner-with-actions/angular.ts b/docs/src/content/examples/hero-banner-with-actions/angular.ts
new file mode 100644
index 0000000000..0e6352d70f
--- /dev/null
+++ b/docs/src/content/examples/hero-banner-with-actions/angular.ts
@@ -0,0 +1,11 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-hero-banner-with-actions",
+ templateUrl: "./angular.html",
+})
+export class HeroBannerWithActionsComponent {
+ onClick(): void {
+ console.log("Call to action clicked");
+ }
+}
diff --git a/docs/src/content/examples/hero-banner-with-actions/index.mdx b/docs/src/content/examples/hero-banner-with-actions/index.mdx
new file mode 100644
index 0000000000..005688ef2b
--- /dev/null
+++ b/docs/src/content/examples/hero-banner-with-actions/index.mdx
@@ -0,0 +1,34 @@
+---
+id: hero-banner-with-actions
+title: Hero banner with actions
+categories:
+ - content-layout
+scale: task
+userType: both
+tags:
+ - hero
+ - banner
+ - cta
+ - landing
+components:
+ - hero-banner
+ - button
+status: published
+---
+
+Create a hero banner with a call-to-action button to guide users toward the primary task on a landing page.
+
+## When to use
+
+Use this pattern when:
+- Creating a landing page for a service
+- You need a prominent call-to-action
+- Introducing users to a service or feature
+- Building a start page for public forms
+
+## Considerations
+
+- Use the "start" button type for primary actions
+- Keep the banner text concise and action-oriented
+- The actions slot positions the button appropriately
+- Ensure the heading clearly describes the service purpose
diff --git a/docs/src/content/examples/hero-banner-with-actions/react.tsx b/docs/src/content/examples/hero-banner-with-actions/react.tsx
new file mode 100644
index 0000000000..6189bf33b0
--- /dev/null
+++ b/docs/src/content/examples/hero-banner-with-actions/react.tsx
@@ -0,0 +1,23 @@
+import {
+ GoabButton,
+ GoabHeroBanner,
+ GoabHeroBannerActions,
+} from "@abgov/react-components";
+
+export function HeroBannerWithActions() {
+ function handleClick() {
+ console.log("Call to action clicked");
+ }
+
+ return (
+
+ Resources are available to help Alberta entrepreneurs and small businesses
+ start, grow and succeed.
+
+
+ Call to action
+
+
+
+ );
+}
diff --git a/docs/src/content/examples/hero-banner-with-actions/web-components.html b/docs/src/content/examples/hero-banner-with-actions/web-components.html
new file mode 100644
index 0000000000..4613a86bc2
--- /dev/null
+++ b/docs/src/content/examples/hero-banner-with-actions/web-components.html
@@ -0,0 +1,12 @@
+
+ Resources are available to help Alberta entrepreneurs and small businesses start, grow and succeed.
+
+ Call to action
+
+
+
+
diff --git a/docs/src/content/examples/hide-and-show-many-sections-of-information/angular.html b/docs/src/content/examples/hide-and-show-many-sections-of-information/angular.html
new file mode 100644
index 0000000000..6fd7b9bf84
--- /dev/null
+++ b/docs/src/content/examples/hide-and-show-many-sections-of-information/angular.html
@@ -0,0 +1,35 @@
+
+ {{ accordionStatus }}
+
+
+
+ To create an account you will need to contact your office admin.
+
+
+
+ You will need to verify your identity through our two factor authentication in addition to the digital signature.
+
+
+
+ Yes, you can see the status of your application on the main service dashboard when you login. You will receive updates and notifications in your email as your request progresses.
+
+
+
+ Yes, our digital service is designed with accessibility in mind. More information on accessibility.
+
diff --git a/docs/src/content/examples/hide-and-show-many-sections-of-information/angular.ts b/docs/src/content/examples/hide-and-show-many-sections-of-information/angular.ts
new file mode 100644
index 0000000000..408d8ff414
--- /dev/null
+++ b/docs/src/content/examples/hide-and-show-many-sections-of-information/angular.ts
@@ -0,0 +1,29 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-hide-and-show-many-sections",
+ templateUrl: "./angular.html",
+})
+export class HideAndShowManySectionsComponent {
+ expandedList: boolean[] = [false, false, false, false];
+ expandedAll = false;
+ accordionStatus = "Show all sections";
+
+ toggleAccordion(index: number, open: boolean): void {
+ this.expandedList[index] = open;
+ this.updateAccordionStatus();
+ }
+
+ onClick(): void {
+ const isExpanding = this.expandedList.some((isOpen) => !isOpen);
+ this.expandedList = this.expandedList.map(() => isExpanding);
+ this.updateAccordionStatus();
+ }
+
+ private updateAccordionStatus(): void {
+ this.expandedAll = this.expandedList.every((isOpen) => isOpen);
+ this.accordionStatus = this.expandedList.every((isOpen) => isOpen)
+ ? "Hide all sections"
+ : "Show all sections";
+ }
+}
diff --git a/docs/src/content/examples/hide-and-show-many-sections-of-information/index.mdx b/docs/src/content/examples/hide-and-show-many-sections-of-information/index.mdx
new file mode 100644
index 0000000000..d22a72a438
--- /dev/null
+++ b/docs/src/content/examples/hide-and-show-many-sections-of-information/index.mdx
@@ -0,0 +1,34 @@
+---
+id: hide-and-show-many-sections-of-information
+title: Hide and show many sections of information
+categories:
+ - content-layout
+scale: task
+userType: both
+tags:
+ - accordion
+ - expand
+ - collapse
+ - faq
+components:
+ - accordion
+ - button
+status: published
+---
+
+Allow users to expand and collapse multiple accordion sections, with a button to show or hide all sections at once.
+
+## When to use
+
+Use this pattern when:
+- Presenting FAQ-style content
+- Users need to scan multiple sections quickly
+- Content is long and would benefit from progressive disclosure
+- Providing a "show all" and "hide all" option improves usability
+
+## Considerations
+
+- Track the open state of each accordion individually
+- Update the button text based on whether all sections are expanded or collapsed
+- Consider keyboard accessibility for the expand/collapse all functionality
+- Accordion headings should be descriptive and scannable
diff --git a/docs/src/content/examples/hide-and-show-many-sections-of-information/react.tsx b/docs/src/content/examples/hide-and-show-many-sections-of-information/react.tsx
new file mode 100644
index 0000000000..126f796127
--- /dev/null
+++ b/docs/src/content/examples/hide-and-show-many-sections-of-information/react.tsx
@@ -0,0 +1,76 @@
+import { useState, useEffect } from "react";
+import { GoabAccordion, GoabButton } from "@abgov/react-components";
+
+export function HideAndShowManySectionsOfInformation() {
+ const [expandedAll, setExpandedAll] = useState(false);
+ const [expandedList, setExpandedList] = useState([]);
+
+ useEffect(() => {
+ setExpandedAll(expandedList.length === 4);
+ }, [expandedList.length]);
+
+ const expandOrCollapseAll = () => {
+ setExpandedAll((prev) => {
+ const newState = !prev;
+ setExpandedList(newState ? [1, 2, 3, 4] : []);
+ return newState;
+ });
+ };
+
+ const updateAccordion = (order: number, isOpen: boolean) => {
+ setExpandedList((prev) => {
+ if (isOpen) {
+ return prev.includes(order) ? prev : [...prev, order];
+ }
+ return prev.filter((item) => item !== order);
+ });
+ };
+
+ return (
+ <>
+ expandOrCollapseAll()}>
+ {expandedAll ? "Hide all sections" : "Show all sections"}
+
+
+ updateAccordion(1, open)}
+ >
+ To create an account you will need to contact your office admin.
+
+
+ updateAccordion(2, open)}
+ >
+ You will need to verify your identity through our two factor
+ authentication in addition to the digital signature.
+
+
+ updateAccordion(3, open)}
+ >
+ Yes, you can see the status of your application on the main service
+ dashboard when you login. You will receive updates and notifications in
+ your email as your request progresses.
+
+
+ updateAccordion(4, open)}
+ >
+ Yes, our digital service is designed with accessibility in mind.{" "}
+ More information on accessibility.
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/hide-and-show-many-sections-of-information/web-components.html b/docs/src/content/examples/hide-and-show-many-sections-of-information/web-components.html
new file mode 100644
index 0000000000..d6f6273cd9
--- /dev/null
+++ b/docs/src/content/examples/hide-and-show-many-sections-of-information/web-components.html
@@ -0,0 +1,63 @@
+
+ Show all sections
+
+
+
+ To create an account you will need to contact your office admin.
+
+
+
+ You will need to verify your identity through our two factor authentication in addition to the digital signature.
+
+
+
+ Yes, you can see the status of your application on the main service dashboard when you login. You will receive updates and notifications in your email as your request progresses.
+
+
+
+ Yes, our digital service is designed with accessibility in mind. More information on accessibility.
+
+
+
diff --git a/docs/src/content/examples/include-a-link-in-the-helper-text-of-an-option/angular.html b/docs/src/content/examples/include-a-link-in-the-helper-text-of-an-option/angular.html
new file mode 100644
index 0000000000..d517b5d6ea
--- /dev/null
+++ b/docs/src/content/examples/include-a-link-in-the-helper-text-of-an-option/angular.html
@@ -0,0 +1,15 @@
+
+
+
+
+ Help text with a link.
+
+
+
+
+
+
diff --git a/docs/src/content/examples/include-a-link-in-the-helper-text-of-an-option/angular.ts b/docs/src/content/examples/include-a-link-in-the-helper-text-of-an-option/angular.ts
new file mode 100644
index 0000000000..30bd4def80
--- /dev/null
+++ b/docs/src/content/examples/include-a-link-in-the-helper-text-of-an-option/angular.ts
@@ -0,0 +1,11 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-include-link-in-helper-text",
+ templateUrl: "./angular.html",
+})
+export class IncludeLinkInHelperTextComponent {
+ optionOne = true;
+ optionTwo = false;
+ optionThree = false;
+}
diff --git a/docs/src/content/examples/include-a-link-in-the-helper-text-of-an-option/index.mdx b/docs/src/content/examples/include-a-link-in-the-helper-text-of-an-option/index.mdx
new file mode 100644
index 0000000000..f1e87fa260
--- /dev/null
+++ b/docs/src/content/examples/include-a-link-in-the-helper-text-of-an-option/index.mdx
@@ -0,0 +1,34 @@
+---
+id: include-a-link-in-the-helper-text-of-an-option
+title: Include a link in the helper text of an option
+categories:
+ - forms
+scale: interaction
+userType: both
+tags:
+ - checkbox
+ - helper-text
+ - links
+ - forms
+components:
+ - checkbox
+ - form-item
+status: published
+---
+
+Add links within the description text of checkbox options to provide additional context or resources while users are making selections.
+
+## When to use
+
+Use this pattern when:
+- Checkbox options need additional context via links
+- Users might need more information before making a selection
+- Linking to terms, policies, or detailed explanations
+- The link is directly relevant to the specific option
+
+## Considerations
+
+- Keep description text concise even with links
+- Ensure link text is descriptive and accessible
+- Consider whether the link should open in a new tab
+- Use the description prop (React) or ng-template (Angular) for custom content
diff --git a/docs/src/content/examples/include-a-link-in-the-helper-text-of-an-option/react.tsx b/docs/src/content/examples/include-a-link-in-the-helper-text-of-an-option/react.tsx
new file mode 100644
index 0000000000..58c291d8bf
--- /dev/null
+++ b/docs/src/content/examples/include-a-link-in-the-helper-text-of-an-option/react.tsx
@@ -0,0 +1,22 @@
+import { GoabCheckbox, GoabCheckboxList, GoabFormItem } from "@abgov/react-components";
+
+export function IncludeALinkInTheHelperTextOfAnOption() {
+ return (
+
+
+
+ Help text with a link.
+
+ }
+ />
+
+
+
+
+ );
+}
diff --git a/docs/src/content/examples/include-a-link-in-the-helper-text-of-an-option/web-components.html b/docs/src/content/examples/include-a-link-in-the-helper-text-of-an-option/web-components.html
new file mode 100644
index 0000000000..4ee3afded4
--- /dev/null
+++ b/docs/src/content/examples/include-a-link-in-the-helper-text-of-an-option/web-components.html
@@ -0,0 +1,9 @@
+
+
+
+ Help text with a link.
+
+
+
+
+
diff --git a/docs/src/content/examples/include-descriptions-for-items-in-a-checkbox-list/angular.html b/docs/src/content/examples/include-descriptions-for-items-in-a-checkbox-list/angular.html
new file mode 100644
index 0000000000..224eb353bb
--- /dev/null
+++ b/docs/src/content/examples/include-descriptions-for-items-in-a-checkbox-list/angular.html
@@ -0,0 +1,20 @@
+
+
+
+
+ Use the account associated with the business
+
+
+
+
+ If you don't have a Alberta.ca login, you can create one
+
+
+
+
diff --git a/docs/src/content/examples/include-descriptions-for-items-in-a-checkbox-list/angular.ts b/docs/src/content/examples/include-descriptions-for-items-in-a-checkbox-list/angular.ts
new file mode 100644
index 0000000000..4d2f2703f1
--- /dev/null
+++ b/docs/src/content/examples/include-descriptions-for-items-in-a-checkbox-list/angular.ts
@@ -0,0 +1,16 @@
+import { Component } from "@angular/core";
+import { FormBuilder, FormGroup } from "@angular/forms";
+
+@Component({
+ selector: "app-include-descriptions-for-items",
+ templateUrl: "./angular.html",
+})
+export class IncludeDescriptionsForItemsComponent {
+ form: FormGroup;
+
+ constructor(private fb: FormBuilder) {
+ this.form = this.fb.group({
+ selectOne: ["1"],
+ });
+ }
+}
diff --git a/docs/src/content/examples/include-descriptions-for-items-in-a-checkbox-list/index.mdx b/docs/src/content/examples/include-descriptions-for-items-in-a-checkbox-list/index.mdx
new file mode 100644
index 0000000000..14fb3f4930
--- /dev/null
+++ b/docs/src/content/examples/include-descriptions-for-items-in-a-checkbox-list/index.mdx
@@ -0,0 +1,34 @@
+---
+id: include-descriptions-for-items-in-a-checkbox-list
+title: Include descriptions for items in a checkbox list
+categories:
+ - forms
+scale: task
+userType: both
+tags:
+ - radio
+ - descriptions
+ - forms
+components:
+ - form-item
+ - radio-group
+ - radio-item
+status: published
+---
+
+Add descriptive text to radio button options to help users understand the implications of each choice.
+
+## When to use
+
+Use this pattern when:
+- Radio options need additional explanation
+- Users might not understand the difference between options
+- Each option has specific implications or requirements
+- Providing context helps users make informed decisions
+
+## Considerations
+
+- Keep descriptions concise but informative
+- Ensure the label and description work together
+- Use consistent description length across options
+- Consider whether all options need descriptions or just some
diff --git a/docs/src/content/examples/include-descriptions-for-items-in-a-checkbox-list/react.tsx b/docs/src/content/examples/include-descriptions-for-items-in-a-checkbox-list/react.tsx
new file mode 100644
index 0000000000..32efe9e8f8
--- /dev/null
+++ b/docs/src/content/examples/include-descriptions-for-items-in-a-checkbox-list/react.tsx
@@ -0,0 +1,31 @@
+import { useState } from "react";
+import {
+ GoabFormItem,
+ GoabRadioGroup,
+ GoabRadioItem,
+} from "@abgov/react-components";
+
+export function IncludeDescriptionsForItemsInACheckboxList() {
+ const [selected, setSelected] = useState("1");
+
+ return (
+
+ setSelected(event.value)}
+ >
+
+
+
+
+ );
+}
diff --git a/docs/src/content/examples/include-descriptions-for-items-in-a-checkbox-list/web-components.html b/docs/src/content/examples/include-descriptions-for-items-in-a-checkbox-list/web-components.html
new file mode 100644
index 0000000000..e434b31a80
--- /dev/null
+++ b/docs/src/content/examples/include-descriptions-for-items-in-a-checkbox-list/web-components.html
@@ -0,0 +1,16 @@
+
+
+
+ Use the account associated with the business
+
+
+ If you don't have a Alberta.ca login, you can create one
+
+
+
+
+
diff --git a/docs/src/content/examples/link-the-user-to-give-feedback-to-the-service/angular.html b/docs/src/content/examples/link-the-user-to-give-feedback-to-the-service/angular.html
new file mode 100644
index 0000000000..126ada6c15
--- /dev/null
+++ b/docs/src/content/examples/link-the-user-to-give-feedback-to-the-service/angular.html
@@ -0,0 +1 @@
+
diff --git a/docs/src/content/examples/link-the-user-to-give-feedback-to-the-service/angular.ts b/docs/src/content/examples/link-the-user-to-give-feedback-to-the-service/angular.ts
new file mode 100644
index 0000000000..e733940ce1
--- /dev/null
+++ b/docs/src/content/examples/link-the-user-to-give-feedback-to-the-service/angular.ts
@@ -0,0 +1,12 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-feedback-link",
+ templateUrl: "./angular.html",
+})
+export class FeedbackLinkComponent {
+ onFeedbackClick(): void {
+ console.log("Feedback clicked");
+ alert("Thank you for your feedback!");
+ }
+}
diff --git a/docs/src/content/examples/link-the-user-to-give-feedback-to-the-service/index.mdx b/docs/src/content/examples/link-the-user-to-give-feedback-to-the-service/index.mdx
new file mode 100644
index 0000000000..aef1d87b91
--- /dev/null
+++ b/docs/src/content/examples/link-the-user-to-give-feedback-to-the-service/index.mdx
@@ -0,0 +1,33 @@
+---
+id: link-the-user-to-give-feedback-to-the-service
+title: Link the user to give feedback to the service
+categories:
+ - feedback-and-alerts
+scale: interaction
+userType: citizen
+tags:
+ - feedback
+ - microsite-header
+ - alpha
+ - beta
+components:
+ - microsite-header
+status: published
+---
+
+Use the microsite header's feedback functionality to collect user feedback during alpha or beta phases of a service.
+
+## When to use
+
+Use this pattern when:
+- Your service is in alpha or beta phase
+- You want to actively collect user feedback
+- Building a citizen-facing government service
+- The service is still being developed and improved
+
+## Considerations
+
+- Use the `onFeedbackClick` handler to define feedback behavior
+- Consider linking to a feedback form or opening a modal
+- The feedback link appears automatically on alpha/beta headers
+- Ensure the feedback mechanism is accessible and easy to use
diff --git a/docs/src/content/examples/link-the-user-to-give-feedback-to-the-service/react.tsx b/docs/src/content/examples/link-the-user-to-give-feedback-to-the-service/react.tsx
new file mode 100644
index 0000000000..b5b07dc633
--- /dev/null
+++ b/docs/src/content/examples/link-the-user-to-give-feedback-to-the-service/react.tsx
@@ -0,0 +1,10 @@
+import { GoabMicrositeHeader } from "@abgov/react-components";
+
+export function LinkTheUserToGiveFeedbackToTheService() {
+ const onClick = () => {
+ console.log("Feedback clicked");
+ alert("Thank you for your feedback!");
+ };
+
+ return ;
+}
diff --git a/docs/src/content/examples/link-the-user-to-give-feedback-to-the-service/web-components.html b/docs/src/content/examples/link-the-user-to-give-feedback-to-the-service/web-components.html
new file mode 100644
index 0000000000..563b930094
--- /dev/null
+++ b/docs/src/content/examples/link-the-user-to-give-feedback-to-the-service/web-components.html
@@ -0,0 +1,8 @@
+
+
+
diff --git a/docs/src/content/examples/link-to-an-external-page/angular.html b/docs/src/content/examples/link-to-an-external-page/angular.html
new file mode 100644
index 0000000000..c3a08d25c7
--- /dev/null
+++ b/docs/src/content/examples/link-to-an-external-page/angular.html
@@ -0,0 +1,3 @@
+
+ External link
+
diff --git a/docs/src/content/examples/link-to-an-external-page/angular.ts b/docs/src/content/examples/link-to-an-external-page/angular.ts
new file mode 100644
index 0000000000..de4e387e21
--- /dev/null
+++ b/docs/src/content/examples/link-to-an-external-page/angular.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-external-link",
+ templateUrl: "./angular.html",
+})
+export class ExternalLinkComponent {}
diff --git a/docs/src/content/examples/link-to-an-external-page/index.mdx b/docs/src/content/examples/link-to-an-external-page/index.mdx
new file mode 100644
index 0000000000..67f51258b1
--- /dev/null
+++ b/docs/src/content/examples/link-to-an-external-page/index.mdx
@@ -0,0 +1,32 @@
+---
+id: link-to-an-external-page
+title: Link to an external page
+categories:
+ - inputs-and-actions
+scale: interaction
+userType: both
+tags:
+ - link
+ - external
+ - navigation
+components:
+ - link
+status: published
+---
+
+Use an external link indicator to show users when a link will take them to a different website.
+
+## When to use
+
+Use this pattern when:
+- Linking to websites outside your service
+- Users should be aware they're leaving the current site
+- Providing references to external resources
+- Following accessibility best practices for external links
+
+## Considerations
+
+- Use the "open" trailing icon to indicate external links
+- Consider whether the link should open in a new tab
+- Ensure the link text clearly describes the destination
+- External links should be used sparingly and with purpose
diff --git a/docs/src/content/examples/link-to-an-external-page/react.tsx b/docs/src/content/examples/link-to-an-external-page/react.tsx
new file mode 100644
index 0000000000..18d8832392
--- /dev/null
+++ b/docs/src/content/examples/link-to-an-external-page/react.tsx
@@ -0,0 +1,9 @@
+import { GoabLink } from "@abgov/react-components";
+
+export function LinkToAnExternalPage() {
+ return (
+
+ External link
+
+ );
+}
diff --git a/docs/src/content/examples/link-to-an-external-page/web-components.html b/docs/src/content/examples/link-to-an-external-page/web-components.html
new file mode 100644
index 0000000000..183d315294
--- /dev/null
+++ b/docs/src/content/examples/link-to-an-external-page/web-components.html
@@ -0,0 +1,3 @@
+
+ External link
+
diff --git a/docs/src/content/examples/public-form/angular.html b/docs/src/content/examples/public-form/angular.html
new file mode 100644
index 0000000000..7319317a54
--- /dev/null
+++ b/docs/src/content/examples/public-form/angular.html
@@ -0,0 +1,40 @@
+
+
+ Primary users: citizens, public, external
+
+ You are designing a public service for citizens. It should be designed to be as simple and intuitive as possible, while ensuring citizens can make complete and informed decisions for themselves using the service.
+
+ There is an emphasis on an accessible experience with a low cognitive load for users who use the service infrequently.
+
+
+
+Pages
+
+
+
+ 1. Start page
+
+ This is the starting point for a citizen to begin your form from within your service or from Alberta.ca.
+
+
+ 2. Task list page (optional)
+
+ Outline the entire process for the user and help them through the process by breaking down an experience into individual tasks.
+
+
+ 3. Question pages
+
+ Ask a user a question or a small set of related questions.
+
+
+ 4. Review page
+
+ Let users check answers before submitting information to a service.
+
+
+ 5. Results page
+
+ Let users know that they've completed a form, application, or task and tell them what to do next.
+
+
+
diff --git a/docs/src/content/examples/public-form/angular.ts b/docs/src/content/examples/public-form/angular.ts
new file mode 100644
index 0000000000..fb2b7a40ae
--- /dev/null
+++ b/docs/src/content/examples/public-form/angular.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-public-form",
+ templateUrl: "./angular.html",
+})
+export class PublicFormComponent {}
diff --git a/docs/src/content/examples/public-form/index.mdx b/docs/src/content/examples/public-form/index.mdx
new file mode 100644
index 0000000000..8875c9533a
--- /dev/null
+++ b/docs/src/content/examples/public-form/index.mdx
@@ -0,0 +1,33 @@
+---
+id: public-form
+title: Public form
+categories:
+ - forms
+scale: service
+userType: citizen
+tags:
+ - form
+ - public
+ - citizen
+ - pattern
+components: []
+status: published
+---
+
+The public form pattern provides a structure for citizen-facing form experiences, emphasizing simplicity, accessibility, and low cognitive load.
+
+## When to use
+
+Use this pattern when:
+- Designing a public service for citizens
+- Building forms that should be simple and intuitive
+- Users need to make informed decisions while completing the form
+- The service should accommodate users who use it infrequently
+
+## Considerations
+
+- Follow the "one idea per page" principle to reduce cognitive load
+- Break complex forms into multiple pages with single questions
+- Use task list pages for longer processes with multiple sections
+- Consider using simple progress indicators rather than horizontal steppers
+- Ensure all form elements meet WCAG 2.2 AA accessibility standards
diff --git a/docs/src/content/examples/public-form/react.tsx b/docs/src/content/examples/public-form/react.tsx
new file mode 100644
index 0000000000..c48b3b3ea7
--- /dev/null
+++ b/docs/src/content/examples/public-form/react.tsx
@@ -0,0 +1,68 @@
+import { GoabDetails, GoabGrid, GoabText } from "@abgov/react-components";
+
+export function PublicForm() {
+ return (
+ <>
+
+
+ Primary users: citizens, public, external
+
+
+ You are designing a public service for citizens. It should be designed
+ to be as simple and intuitive as possible, while ensuring citizens can
+ make complete and informed decisions for themselves using the service.
+
+
+ There is an emphasis on an accessible experience with a low cognitive
+ load for users who use the service infrequently.
+
+
+
+
+ Pages
+
+
+
+
+
+ 1. Start page
+
+
+ This is the starting point for a citizen to begin your form from
+ within your service or from Alberta.ca.
+
+
+
+ 2. Task list page (optional)
+
+
+ Outline the entire process for the user and help them through the
+ process by breaking down an experience into individual tasks.
+
+
+
+ 3. Question pages
+
+
+ Ask a user a question or a small set of related questions.
+
+
+
+ 4. Review page
+
+
+ Let users check answers before submitting information to a service.
+
+
+
+ 5. Results page
+
+
+ Let users know that they've completed a form, application, or task
+ and tell them what to do next.
+
+
+ You are designing a public service for citizens. It should be designed to be as simple and intuitive as possible, while ensuring citizens can make complete and informed decisions for themselves using the service.
+
+ There is an emphasis on an accessible experience with a low cognitive load for users who use the service infrequently.
+
+
+
+Pages
+
+
+
+ 1. Start page
+
+ This is the starting point for a citizen to begin your form from within your service or from Alberta.ca.
+
+
+ 2. Task list page (optional)
+
+ Outline the entire process for the user and help them through the process by breaking down an experience into individual tasks.
+
+
+ 3. Question pages
+
+ Ask a user a question or a small set of related questions.
+
+
+ 4. Review page
+
+ Let users check answers before submitting information to a service.
+
+
+ 5. Results page
+
+ Let users know that they've completed a form, application, or task and tell them what to do next.
+
+
+
diff --git a/docs/src/content/examples/question-page/angular.html b/docs/src/content/examples/question-page/angular.html
new file mode 100644
index 0000000000..4ae4f28070
--- /dev/null
+++ b/docs/src/content/examples/question-page/angular.html
@@ -0,0 +1,22 @@
+
+ Back
+
+
+What is your email address?
+We'll use this to send you confirmation of your application.
+
+
+
+
+
+
+
+
+ Continue
+
+
diff --git a/docs/src/content/examples/question-page/angular.ts b/docs/src/content/examples/question-page/angular.ts
new file mode 100644
index 0000000000..ecc8000b24
--- /dev/null
+++ b/docs/src/content/examples/question-page/angular.ts
@@ -0,0 +1,17 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-question-page",
+ templateUrl: "./angular.html",
+})
+export class QuestionPageComponent {
+ answer = "";
+
+ onAnswerChange(event: { value: string }): void {
+ this.answer = event.value;
+ }
+
+ handleContinue(): void {
+ console.log("Answer submitted:", this.answer);
+ }
+}
diff --git a/docs/src/content/examples/question-page/index.mdx b/docs/src/content/examples/question-page/index.mdx
new file mode 100644
index 0000000000..2149602111
--- /dev/null
+++ b/docs/src/content/examples/question-page/index.mdx
@@ -0,0 +1,37 @@
+---
+id: question-page
+title: Question page
+categories:
+ - forms
+scale: page
+userType: citizen
+tags:
+ - forms
+ - question
+ - wizard
+ - one-thing-per-page
+components:
+ - form-item
+ - input
+ - button
+ - button-group
+status: published
+---
+
+A question page pattern that presents one question at a time to help users focus, reduce cognitive load, and navigate complex forms more easily.
+
+## When to use
+
+Use this pattern when:
+- Building multi-step forms or wizards
+- Asking users for information that requires focused attention
+- The form has branching logic based on user responses
+- You want to reduce cognitive load and errors
+
+## Considerations
+
+- Each page should contain one idea: one question, one decision, or one piece of information
+- Progress indicators are optional - test without one first
+- The pattern helps with mobile responsiveness and accessibility
+- Enables automatic saving and better error handling
+- Consider adaptive questioning where subsequent questions depend on previous answers
diff --git a/docs/src/content/examples/question-page/react.tsx b/docs/src/content/examples/question-page/react.tsx
new file mode 100644
index 0000000000..ca4a8b2649
--- /dev/null
+++ b/docs/src/content/examples/question-page/react.tsx
@@ -0,0 +1,44 @@
+import { useState } from "react";
+import {
+ GoabButton,
+ GoabButtonGroup,
+ GoabFormItem,
+ GoabInput,
+ GoabLink,
+ GoabText,
+} from "@abgov/react-components";
+
+export function QuestionPage() {
+ const [answer, setAnswer] = useState("");
+
+ const handleContinue = () => {
+ console.log("Answer submitted:", answer);
+ };
+
+ return (
+ <>
+
+ Back
+
+
+ What is your email address?
+ We'll use this to send you confirmation of your application.
+
+
+ setAnswer(e.value)}
+ width="100%"
+ />
+
+
+
+
+ Continue
+
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/question-page/web-components.html b/docs/src/content/examples/question-page/web-components.html
new file mode 100644
index 0000000000..eed889012f
--- /dev/null
+++ b/docs/src/content/examples/question-page/web-components.html
@@ -0,0 +1,35 @@
+
+ Back
+
+
+What is your email address?
+We'll use this to send you confirmation of your application.
+
+
+
+
+
+
+
+
+ Continue
+
+
+
+
diff --git a/docs/src/content/examples/remove-a-filter/angular.html b/docs/src/content/examples/remove-a-filter/angular.html
new file mode 100644
index 0000000000..b62495f8ab
--- /dev/null
+++ b/docs/src/content/examples/remove-a-filter/angular.html
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/docs/src/content/examples/remove-a-filter/angular.ts b/docs/src/content/examples/remove-a-filter/angular.ts
new file mode 100644
index 0000000000..2b0c6b8da5
--- /dev/null
+++ b/docs/src/content/examples/remove-a-filter/angular.ts
@@ -0,0 +1,13 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-remove-a-filter",
+ templateUrl: "./angular.html",
+})
+export class RemoveAFilterComponent {
+ chips: string[] = ["Chip 1", "Chip 2", "Chip 3"];
+
+ deleteChip(chip: string): void {
+ this.chips = this.chips.filter((c) => c !== chip);
+ }
+}
diff --git a/docs/src/content/examples/remove-a-filter/index.mdx b/docs/src/content/examples/remove-a-filter/index.mdx
new file mode 100644
index 0000000000..1e25f6486e
--- /dev/null
+++ b/docs/src/content/examples/remove-a-filter/index.mdx
@@ -0,0 +1,31 @@
+---
+id: remove-a-filter
+title: Remove a filter
+categories:
+ - inputs-and-actions
+scale: interaction
+userType: both
+tags:
+ - filtering
+ - chips
+ - remove
+components:
+ - filter-chip
+status: published
+---
+
+Allow users to remove active filters by clicking on filter chips, providing clear visual feedback and dynamic updates to filtered results.
+
+## When to use
+
+Use this pattern when:
+- Users have applied filters that need to be removable
+- You want to show active filter state clearly
+- Filters should be easy to remove with a single click
+
+## Considerations
+
+- Each chip should clearly indicate what filter it represents
+- Provide visual feedback when removing filters
+- Results should update immediately when a filter is removed
+- Consider adding an "x" icon or clear affordance to indicate removeability
diff --git a/docs/src/content/examples/remove-a-filter/react.tsx b/docs/src/content/examples/remove-a-filter/react.tsx
new file mode 100644
index 0000000000..f8cd35f185
--- /dev/null
+++ b/docs/src/content/examples/remove-a-filter/react.tsx
@@ -0,0 +1,23 @@
+import { useState } from "react";
+import { GoabFilterChip } from "@abgov/react-components";
+
+export function RemoveAFilter() {
+ const [chips, setChips] = useState(["Chip 1", "Chip 2", "Chip 3"]);
+
+ const deleteChip = (chip: string) => {
+ setChips((prevChips) => prevChips.filter((c) => c !== chip));
+ };
+
+ return (
+
+
+
+ Back
+ Continue
+
+
+
diff --git a/docs/src/content/examples/require-user-action-before-continuing/angular.ts b/docs/src/content/examples/require-user-action-before-continuing/angular.ts
new file mode 100644
index 0000000000..f7a8fc125b
--- /dev/null
+++ b/docs/src/content/examples/require-user-action-before-continuing/angular.ts
@@ -0,0 +1,13 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-require-user-action-before-continuing",
+ templateUrl: "./angular.html",
+})
+export class RequireUserActionBeforeContinuingComponent {
+ open = false;
+
+ toggleModal(): void {
+ this.open = !this.open;
+ }
+}
diff --git a/docs/src/content/examples/require-user-action-before-continuing/index.mdx b/docs/src/content/examples/require-user-action-before-continuing/index.mdx
new file mode 100644
index 0000000000..580402ef63
--- /dev/null
+++ b/docs/src/content/examples/require-user-action-before-continuing/index.mdx
@@ -0,0 +1,36 @@
+---
+id: require-user-action-before-continuing
+title: Require user action before continuing
+categories:
+ - forms
+scale: task
+userType: both
+tags:
+ - modal
+ - confirmation
+ - warning
+ - action
+components:
+ - modal
+ - button
+ - button-group
+status: published
+---
+
+Use a modal dialog to require users to confirm an action before proceeding, especially for irreversible operations or important decision points.
+
+## When to use
+
+Use this pattern when:
+- The user is about to perform an action that cannot be undone
+- Navigation will cause data loss or prevent returning
+- Important information needs acknowledgment before proceeding
+- Users should confirm before submitting important forms
+
+## Considerations
+
+- Clearly explain the consequences of continuing
+- Provide a way to go back or cancel
+- Use clear, action-oriented button labels
+- Keep the modal content concise and focused
+- Ensure the primary action stands out from secondary options
diff --git a/docs/src/content/examples/require-user-action-before-continuing/react.tsx b/docs/src/content/examples/require-user-action-before-continuing/react.tsx
new file mode 100644
index 0000000000..dd279c564d
--- /dev/null
+++ b/docs/src/content/examples/require-user-action-before-continuing/react.tsx
@@ -0,0 +1,33 @@
+import { useState } from "react";
+import {
+ GoabButton,
+ GoabButtonGroup,
+ GoabModal,
+} from "@abgov/react-components";
+
+export function RequireUserActionBeforeContinuing() {
+ const [open, setOpen] = useState(false);
+
+ return (
+ <>
+ setOpen(true)}>Open Basic Modal
+ setOpen(false)}
+ actions={
+
+ setOpen(false)}>
+ Back
+
+ setOpen(false)}>
+ Continue
+
+
+ }
+ >
+
+
+
+
diff --git a/docs/src/content/examples/reset-date-picker-field/angular.html b/docs/src/content/examples/reset-date-picker-field/angular.html
new file mode 100644
index 0000000000..c4855bc019
--- /dev/null
+++ b/docs/src/content/examples/reset-date-picker-field/angular.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+ Set Value
+ Clear Value
+
diff --git a/docs/src/content/examples/reset-date-picker-field/angular.ts b/docs/src/content/examples/reset-date-picker-field/angular.ts
new file mode 100644
index 0000000000..84cee8353a
--- /dev/null
+++ b/docs/src/content/examples/reset-date-picker-field/angular.ts
@@ -0,0 +1,23 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-reset-date-picker-field",
+ templateUrl: "./angular.html",
+})
+export class ResetDatePickerFieldComponent {
+ item: Date | undefined = undefined;
+
+ onChange(event: { value: Date | undefined }): void {
+ this.item = event.value;
+ }
+
+ setValue(): void {
+ const d = new Date();
+ d.setDate(d.getDate() - 7);
+ this.item = d;
+ }
+
+ clearValue(): void {
+ this.item = undefined;
+ }
+}
diff --git a/docs/src/content/examples/reset-date-picker-field/index.mdx b/docs/src/content/examples/reset-date-picker-field/index.mdx
new file mode 100644
index 0000000000..5d6cc47e6e
--- /dev/null
+++ b/docs/src/content/examples/reset-date-picker-field/index.mdx
@@ -0,0 +1,36 @@
+---
+id: reset-date-picker-field
+title: Reset date picker field
+categories:
+ - inputs-and-actions
+scale: interaction
+userType: both
+tags:
+ - date-picker
+ - form
+ - reset
+ - clear
+components:
+ - date-picker
+ - form-item
+ - button
+ - button-group
+status: published
+---
+
+Allow users to programmatically set or clear a date picker field value, useful for reset functionality or setting default dates.
+
+## When to use
+
+Use this pattern when:
+- Users need to clear a date field to start over
+- You need to set a default or suggested date value
+- Providing quick actions to modify date values
+- Building forms with reset functionality
+
+## Considerations
+
+- Provide clear button labels indicating the action
+- Consider whether clearing should also reset validation state
+- The date picker should update immediately when set or cleared
+- Consider providing a confirmation for clearing important dates
diff --git a/docs/src/content/examples/reset-date-picker-field/react.tsx b/docs/src/content/examples/reset-date-picker-field/react.tsx
new file mode 100644
index 0000000000..29e3e77f62
--- /dev/null
+++ b/docs/src/content/examples/reset-date-picker-field/react.tsx
@@ -0,0 +1,45 @@
+import { useState } from "react";
+import {
+ GoabButton,
+ GoabButtonGroup,
+ GoabDatePicker,
+ GoabFormItem,
+} from "@abgov/react-components";
+
+export function ResetDatePickerField() {
+ const [date, setDate] = useState();
+
+ const setNewDate = (value: Date | undefined) => {
+ setDate(value);
+ };
+
+ function setValue() {
+ const d = new Date();
+ d.setDate(d.getDate() - 7);
+ setDate(d);
+ }
+
+ function clearValue() {
+ setDate(undefined);
+ }
+
+ return (
+ <>
+
+ setNewDate(e.value as Date)}
+ mb="xl"
+ />
+
+
+
+
+ Set Value
+
+ Clear Value
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/reset-date-picker-field/web-components.html b/docs/src/content/examples/reset-date-picker-field/web-components.html
new file mode 100644
index 0000000000..04852d1851
--- /dev/null
+++ b/docs/src/content/examples/reset-date-picker-field/web-components.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+ Set Value
+ Clear Value
+
+
+
diff --git a/docs/src/content/examples/result-page/angular.html b/docs/src/content/examples/result-page/angular.html
new file mode 100644
index 0000000000..a095b78667
--- /dev/null
+++ b/docs/src/content/examples/result-page/angular.html
@@ -0,0 +1,16 @@
+You have completed the application
+
+
+ You will receive a copy of the confirmation to the email name@email.com
+ Your reference number is: 1234ABC
+
+
+What happens next
+We've sent your application to service name. They will contact you to confirm your registration.
+You can now close this window.
+What did you think of this service? Give feedback
+
+If you have questions about your application
+Contact the [ministry area].
+Email: information@gov.ab.ca
+Phone: 780 123 4567
diff --git a/docs/src/content/examples/result-page/angular.ts b/docs/src/content/examples/result-page/angular.ts
new file mode 100644
index 0000000000..1359827b9e
--- /dev/null
+++ b/docs/src/content/examples/result-page/angular.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-result-page",
+ templateUrl: "./angular.html",
+})
+export class ResultPageComponent {}
diff --git a/docs/src/content/examples/result-page/index.mdx b/docs/src/content/examples/result-page/index.mdx
new file mode 100644
index 0000000000..494563981a
--- /dev/null
+++ b/docs/src/content/examples/result-page/index.mdx
@@ -0,0 +1,36 @@
+---
+id: result-page
+title: Result page
+categories:
+ - forms
+scale: page
+userType: citizen
+tags:
+ - confirmation
+ - success
+ - completion
+ - forms
+components:
+ - block
+ - callout
+status: published
+---
+
+A result page shown after form submission to confirm success, provide next steps, and offer relevant contact information.
+
+## When to use
+
+Use this pattern when:
+- A user has submitted a form or application
+- You need to confirm successful completion of a process
+- There is important follow-up information to communicate
+- Users need reference numbers or confirmation details
+
+## Considerations
+
+- Include a reference number if applicable
+- Clearly explain what happens next and when
+- Provide a way to save or print the confirmation
+- Include service contact information for questions
+- Link to feedback forms and related services
+- Keep the success message clear and reassuring
diff --git a/docs/src/content/examples/result-page/react.tsx b/docs/src/content/examples/result-page/react.tsx
new file mode 100644
index 0000000000..7cfaacb6b4
--- /dev/null
+++ b/docs/src/content/examples/result-page/react.tsx
@@ -0,0 +1,24 @@
+import { GoabCallout, GoabText } from "@abgov/react-components";
+
+export function ResultPage() {
+ return (
+ <>
+ You have completed the application
+
+
+ You will receive a copy of the confirmation to the email name@email.com
+ Your reference number is: 1234ABC
+
+
+ What happens next
+ We've sent your application to service name. They will contact you to confirm your registration.
+ You can now close this window.
+ What did you think of this service? Give feedback
+
+ If you have questions about your application
+ Contact the [ministry area].
+ Email: information@gov.ab.ca
+ Phone: 780 123 4567
+ >
+ );
+}
diff --git a/docs/src/content/examples/result-page/web-components.html b/docs/src/content/examples/result-page/web-components.html
new file mode 100644
index 0000000000..c5116be08c
--- /dev/null
+++ b/docs/src/content/examples/result-page/web-components.html
@@ -0,0 +1,16 @@
+You have completed the application
+
+
+ You will receive a copy of the confirmation to the email name@email.com
+ Your reference number is: 1234ABC
+
+
+What happens next
+We've sent your application to service name. They will contact you to confirm your registration.
+You can now close this window.
+What did you think of this service? Give feedback
+
+If you have questions about your application
+Contact the [ministry area].
+Email: information@gov.ab.ca
+Phone: 780 123 4567
diff --git a/docs/src/content/examples/reveal-input-based-on-a-selection/angular.html b/docs/src/content/examples/reveal-input-based-on-a-selection/angular.html
new file mode 100644
index 0000000000..87f160ccee
--- /dev/null
+++ b/docs/src/content/examples/reveal-input-based-on-a-selection/angular.html
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/examples/reveal-input-based-on-a-selection/angular.ts b/docs/src/content/examples/reveal-input-based-on-a-selection/angular.ts
new file mode 100644
index 0000000000..ecae2f226d
--- /dev/null
+++ b/docs/src/content/examples/reveal-input-based-on-a-selection/angular.ts
@@ -0,0 +1,21 @@
+import { Component } from "@angular/core";
+import { FormBuilder, FormGroup } from "@angular/forms";
+
+@Component({
+ selector: "app-reveal-input-based-on-a-selection",
+ templateUrl: "./angular.html",
+})
+export class RevealInputBasedOnASelectionComponent {
+ form: FormGroup;
+
+ constructor(private fb: FormBuilder) {
+ this.form = this.fb.group({
+ contactMethod: [""],
+ phoneNumber: [""],
+ emailAddress: [""],
+ emailContactMethod: [false],
+ phoneContactMethod: [false],
+ textContactMethod: [false],
+ });
+ }
+}
diff --git a/docs/src/content/examples/reveal-input-based-on-a-selection/index.mdx b/docs/src/content/examples/reveal-input-based-on-a-selection/index.mdx
new file mode 100644
index 0000000000..c83520e37a
--- /dev/null
+++ b/docs/src/content/examples/reveal-input-based-on-a-selection/index.mdx
@@ -0,0 +1,39 @@
+---
+id: reveal-input-based-on-a-selection
+title: Reveal input based on a selection
+categories:
+ - forms
+scale: task
+userType: both
+tags:
+ - conditional
+ - reveal
+ - radio
+ - checkbox
+ - progressive-disclosure
+components:
+ - radio-group
+ - radio-item
+ - checkbox
+ - form-item
+ - input
+status: published
+---
+
+Progressively reveal additional form fields based on user selections, reducing visual complexity while gathering necessary information.
+
+## When to use
+
+Use this pattern when:
+- Additional information is only needed for certain options
+- You want to reduce initial form complexity
+- Follow-up questions depend on user choices
+- Creating a more focused, less overwhelming form experience
+
+## Considerations
+
+- The revealed input should appear directly below the triggering selection
+- Use clear labels that explain what information is needed
+- Ensure the reveal animation is smooth and noticeable
+- Consider what happens to data if the user changes their selection
+- Works with both radio groups (single selection) and checkboxes (multiple selections)
diff --git a/docs/src/content/examples/reveal-input-based-on-a-selection/react.tsx b/docs/src/content/examples/reveal-input-based-on-a-selection/react.tsx
new file mode 100644
index 0000000000..47ba89259e
--- /dev/null
+++ b/docs/src/content/examples/reveal-input-based-on-a-selection/react.tsx
@@ -0,0 +1,96 @@
+import { useState } from "react";
+import {
+ GoabCheckbox,
+ GoabCheckboxList,
+ GoabFormItem,
+ GoabInput,
+ GoabRadioGroup,
+ GoabRadioItem,
+} from "@abgov/react-components";
+
+export function RevealInputBasedOnASelection() {
+ const [contactMethod, setContactMethod] = useState("");
+ const [checkboxSelection, setCheckboxSelection] = useState([]);
+
+ return (
+ <>
+
+ setContactMethod(e.value)}
+ >
+
+ {}} value="" />
+
+ }
+ />
+
+ {}} value="" />
+
+ }
+ />
+
+ {}} value="" />
+
+ }
+ />
+
+
+
+
+ setCheckboxSelection(e.values || [])}
+ >
+
+ {}} value="" />
+
+ }
+ />
+
+ {}} value="" />
+
+ }
+ />
+
+ {}} value="" />
+
+ }
+ />
+
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/reveal-input-based-on-a-selection/web-components.html b/docs/src/content/examples/reveal-input-based-on-a-selection/web-components.html
new file mode 100644
index 0000000000..6a7d353aac
--- /dev/null
+++ b/docs/src/content/examples/reveal-input-based-on-a-selection/web-components.html
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/examples/review-and-action/angular.html b/docs/src/content/examples/review-and-action/angular.html
new file mode 100644
index 0000000000..c78fff73aa
--- /dev/null
+++ b/docs/src/content/examples/review-and-action/angular.html
@@ -0,0 +1,70 @@
+
+
+ Appearance details
+
+
+ Accused name
+ Doe, John Scott
+
+
+
+ Date of birth
+ Mar 14, 2021
+
+
+
+ Court location
+ Calgary
+
+
+
+ Upcoming appearance date(s)
+ Sep 20, 2021
+
+
+
+ Docket number(s) & charges
+
+ 1) 12345678
+ CC 334(1) - Theft under $5000
+ CC 268(1) - Aggravated assault
+
+
+
+ 2) 12345678
+ CC 334(1) - Theft under $5000
+ CC 268(1) - Aggravated assault
+
+
+
+
+
+
+
diff --git a/docs/src/content/examples/review-and-action/angular.ts b/docs/src/content/examples/review-and-action/angular.ts
new file mode 100644
index 0000000000..b1da7c7be8
--- /dev/null
+++ b/docs/src/content/examples/review-and-action/angular.ts
@@ -0,0 +1,50 @@
+import { Component } from "@angular/core";
+import { FormBuilder, FormGroup } from "@angular/forms";
+
+@Component({
+ selector: "app-review-and-action",
+ templateUrl: "./angular.html",
+ styles: [
+ `
+ h3.review-h3 {
+ margin-bottom: var(--goa-space-m);
+ }
+ label.review-label {
+ font: var(--goa-typography-body-s);
+ color: var(--goa-color-text-secondary);
+ }
+ .review-content {
+ font: var(--goa-typography-body-m);
+ }
+ p.review-content {
+ margin-bottom: 0;
+ }
+ h5.review-h5 {
+ font: var(--goa-typography-body-m);
+ color: var(--goa-color-text-secondary);
+ margin-top: var(--goa-space-m);
+ margin-bottom: var(--goa-space-m);
+ }
+ h6.review-h6 {
+ font: var(--goa-typography-heading-s);
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+ `,
+ ],
+})
+export class ReviewAndActionComponent {
+ form: FormGroup;
+
+ constructor(private fb: FormBuilder) {
+ this.form = this.fb.group({
+ case: [""],
+ reason: [""],
+ message: [""],
+ });
+ }
+
+ onClick(): void {
+ console.log("Confirm clicked!");
+ }
+}
diff --git a/docs/src/content/examples/review-and-action/index.mdx b/docs/src/content/examples/review-and-action/index.mdx
new file mode 100644
index 0000000000..bce9cfdeff
--- /dev/null
+++ b/docs/src/content/examples/review-and-action/index.mdx
@@ -0,0 +1,43 @@
+---
+id: review-and-action
+title: Review and action
+categories:
+ - structure-and-navigation
+scale: task
+userType: worker
+tags:
+ - review
+ - action
+ - container
+ - case-management
+ - worker
+components:
+ - container
+ - grid
+ - block
+ - form-item
+ - radio-group
+ - dropdown
+ - text-area
+ - button
+status: published
+---
+
+A side-by-side layout for workers to review case details while taking an action, commonly used in case management and approval workflows.
+
+## When to use
+
+Use this pattern when:
+- Workers need to review information while making decisions
+- Processing applications, requests, or case files
+- The decision requires context from existing case data
+- Actions like approve, deny, or escalate are needed
+
+## Considerations
+
+- Place read-only review information on the left
+- Place action form controls on the right
+- Use containers to group related information
+- Provide clear labels for all case details
+- Include reason fields when denying requests
+- Consider responsive behavior for smaller screens
diff --git a/docs/src/content/examples/review-and-action/react.tsx b/docs/src/content/examples/review-and-action/react.tsx
new file mode 100644
index 0000000000..fa4d4a622f
--- /dev/null
+++ b/docs/src/content/examples/review-and-action/react.tsx
@@ -0,0 +1,90 @@
+import {
+ GoabBlock,
+ GoabButton,
+ GoabContainer,
+ GoabDropdown,
+ GoabDropdownItem,
+ GoabFormItem,
+ GoabGrid,
+ GoabRadioGroup,
+ GoabRadioItem,
+ GoabText,
+ GoabTextarea,
+} from "@abgov/react-components";
+
+export function ReviewAndAction() {
+ return (
+
+
+ Appearance details
+
+
+ Accused name
+ Doe, John Scott
+
+
+
+ Date of birth
+ Mar 14, 2021
+
+
+
+ Court location
+ Calgary
+
+
+
+ Upcoming appearance date(s)
+ Sep 20, 2021
+
+
+
+ Docket number(s) & charges
+
+ 1) 12345678
+ CC 334(1) - Theft under $5000
+ CC 268(1) - Aggravated assault
+
+
+
+ 2) 12345678
+ CC 334(1) - Theft under $5000
+ CC 268(1) - Aggravated assault
+
+
+
+
+
+
+
+ );
+}
diff --git a/docs/src/content/examples/review-and-action/web-components.html b/docs/src/content/examples/review-and-action/web-components.html
new file mode 100644
index 0000000000..89016d00fc
--- /dev/null
+++ b/docs/src/content/examples/review-and-action/web-components.html
@@ -0,0 +1,76 @@
+
+
+ Appearance details
+
+
+ Accused name
+ Doe, John Scott
+
+
+
+ Date of birth
+ Mar 14, 2021
+
+
+
+ Court location
+ Calgary
+
+
+
+ Upcoming appearance date(s)
+ Sep 20, 2021
+
+
+
+ Docket number(s) & charges
+
+ 1) 12345678
+ CC 334(1) - Theft under $5000
+ CC 268(1) - Aggravated assault
+
+
+
+ 2) 12345678
+ CC 334(1) - Theft under $5000
+ CC 268(1) - Aggravated assault
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/examples/review-page/angular.html b/docs/src/content/examples/review-page/angular.html
new file mode 100644
index 0000000000..37a53d2728
--- /dev/null
+++ b/docs/src/content/examples/review-page/angular.html
@@ -0,0 +1,45 @@
+Review your answers
+Your situation
+
+
+
+
What was your (the applicant's) relationship to the deceased?
+
Other
+
Change
+
+
+
My relationship to the deceased was
+
Manager
+
Change
+
+
+
Was the deceased part of a household that was receiving Assured Income for the Severely Handicapped (AISH) or Income Support?
+
No
+
Change
+
+
+
Was the deceased a minor?
+
No
+
Change
+
+
+
What was the deceased's marital status at time of death?
+
Married
+
Change
+
+
+
Did the deceased have any dependents?
+
No
+
Change
+
+
+
Was the deceased a sponsored immigrant?
+
Yes
+
Change
+
+
+
+
+ Confirm and continue
+ Back to application overview
+
diff --git a/docs/src/content/examples/review-page/angular.ts b/docs/src/content/examples/review-page/angular.ts
new file mode 100644
index 0000000000..30fffd6979
--- /dev/null
+++ b/docs/src/content/examples/review-page/angular.ts
@@ -0,0 +1,31 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-review-page",
+ templateUrl: "./angular.html",
+ styles: [
+ `
+ h2.section-title {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+ h2.section-title + h3 {
+ margin-top: var(--goa-space-l);
+ color: var(--goa-color-text-secondary);
+ }
+ `,
+ ],
+})
+export class ReviewPageComponent {
+ onChangeClick(): void {
+ console.log("Change clicked");
+ }
+
+ onConfirmClick(): void {
+ console.log("Confirm clicked");
+ }
+
+ onBackClick(): void {
+ console.log("Back clicked");
+ }
+}
diff --git a/docs/src/content/examples/review-page/index.mdx b/docs/src/content/examples/review-page/index.mdx
new file mode 100644
index 0000000000..eb5f858915
--- /dev/null
+++ b/docs/src/content/examples/review-page/index.mdx
@@ -0,0 +1,37 @@
+---
+id: review-page
+title: Review page
+categories:
+ - forms
+scale: page
+userType: citizen
+tags:
+ - review
+ - check-answers
+ - forms
+ - submission
+components:
+ - table
+ - button
+ - button-group
+status: published
+---
+
+A review page where users can check their answers before submitting a form, with options to change individual responses.
+
+## When to use
+
+Use this pattern when:
+- Users need to review their form answers before submission
+- At the end of a multi-step form or wizard
+- Before finalizing applications or important submissions
+- When accuracy of submitted information is critical
+
+## Considerations
+
+- Display all answered questions with current values
+- Provide "Change" links for each answer
+- Show "Not provided" for skipped optional questions
+- Include visually hidden text in change links for accessibility
+- Consider grouping related answers under section headings
+- For large forms, consider review pages at the end of each section
diff --git a/docs/src/content/examples/review-page/react.tsx b/docs/src/content/examples/review-page/react.tsx
new file mode 100644
index 0000000000..533242cd8e
--- /dev/null
+++ b/docs/src/content/examples/review-page/react.tsx
@@ -0,0 +1,90 @@
+import {
+ GoabButton,
+ GoabButtonGroup,
+ GoabLink,
+ GoabTable,
+ GoabText,
+} from "@abgov/react-components";
+
+export function ReviewPage() {
+ return (
+ <>
+ Review your answers
+ Your situation
+
+
+
+
+ What was your (the applicant's) relationship to the deceased?
+
+
Other
+
+ Change
+
+
+
+
+ My relationship to the deceased was
+
+
Manager
+
+ Change
+
+
+
+
+
+ Was the deceased part of a household that was receiving Assured Income for the
+ Severely Handicapped (AISH) or Income Support?
+
+
+
No
+
+ Change
+
+
+
+
+ Was the deceased a minor?
+
+
No
+
+ Change
+
+
+
+
+ What was the deceased's marital status at time of death?
+
+
Married
+
+ Change
+
+
+
+
+ Did the deceased have any dependents?
+
+
No
+
+ Change
+
+
+
+
+ Was the deceased a sponsored immigrant?
+
+
Yes
+
+ Change
+
+
+
+
+
+ Confirm and continue
+ Back to application overview
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/review-page/web-components.html b/docs/src/content/examples/review-page/web-components.html
new file mode 100644
index 0000000000..125feaa849
--- /dev/null
+++ b/docs/src/content/examples/review-page/web-components.html
@@ -0,0 +1,53 @@
+Review your answers
+Your situation
+
+
+
+
+
What was your (the applicant's) relationship to the deceased?
+
Other
+
Change
+
+
+
My relationship to the deceased was
+
Manager
+
Change
+
+
+
Was the deceased part of a household that was receiving Assured Income for the Severely Handicapped (AISH) or Income Support?
+
No
+
Change
+
+
+
Was the deceased a minor?
+
No
+
Change
+
+
+
What was the deceased's marital status at time of death?
+
Married
+
Change
+
+
+
Did the deceased have any dependents?
+
No
+
Change
+
+
+
Was the deceased a sponsored immigrant?
+
Yes
+
Change
+
+
+
+
+
+ Confirm and continue
+ Back to application overview
+
+
+
diff --git a/docs/src/content/examples/search/angular.html b/docs/src/content/examples/search/angular.html
new file mode 100644
index 0000000000..e42090aee3
--- /dev/null
+++ b/docs/src/content/examples/search/angular.html
@@ -0,0 +1,13 @@
+
diff --git a/docs/src/content/examples/search/angular.ts b/docs/src/content/examples/search/angular.ts
new file mode 100644
index 0000000000..cf3f7bc27b
--- /dev/null
+++ b/docs/src/content/examples/search/angular.ts
@@ -0,0 +1,20 @@
+import { Component } from "@angular/core";
+import { FormBuilder, FormGroup } from "@angular/forms";
+
+@Component({
+ selector: "app-search",
+ templateUrl: "./angular.html",
+})
+export class SearchComponent {
+ form: FormGroup;
+
+ constructor(private fb: FormBuilder) {
+ this.form = this.fb.group({
+ search: [""],
+ });
+ }
+
+ onClick(): void {
+ console.log("search:", this.form.controls["search"].value);
+ }
+}
diff --git a/docs/src/content/examples/search/index.mdx b/docs/src/content/examples/search/index.mdx
new file mode 100644
index 0000000000..b12db13016
--- /dev/null
+++ b/docs/src/content/examples/search/index.mdx
@@ -0,0 +1,36 @@
+---
+id: search
+title: Search
+categories:
+ - inputs-and-actions
+scale: task
+userType: both
+tags:
+ - search
+ - input
+ - filtering
+components:
+ - input
+ - button
+ - block
+ - form-item
+status: published
+---
+
+A search input pattern with a search icon and button for users to find content or filter results.
+
+## When to use
+
+Use this pattern when:
+- Users need to search through content or data
+- Filtering a list or table by text input
+- Providing a site-wide or section search
+- Quick access to specific records is needed
+
+## Considerations
+
+- Include a leading search icon for clear affordance
+- Use an explicit search button for clarity
+- Consider search suggestions or autocomplete for large datasets
+- Provide clear feedback when no results are found
+- Keep the search input appropriately sized for expected query length
diff --git a/docs/src/content/examples/search/react.tsx b/docs/src/content/examples/search/react.tsx
new file mode 100644
index 0000000000..c232e95774
--- /dev/null
+++ b/docs/src/content/examples/search/react.tsx
@@ -0,0 +1,34 @@
+import { useState } from "react";
+import {
+ GoabBlock,
+ GoabButton,
+ GoabFormItem,
+ GoabInput,
+} from "@abgov/react-components";
+
+export function Search() {
+ const [search, setSearch] = useState("");
+
+ const onClick = () => {
+ console.log("search:", search);
+ };
+
+ return (
+
+ );
+}
diff --git a/docs/src/content/examples/search/web-components.html b/docs/src/content/examples/search/web-components.html
new file mode 100644
index 0000000000..ebd047dfb2
--- /dev/null
+++ b/docs/src/content/examples/search/web-components.html
@@ -0,0 +1,27 @@
+
+
+
diff --git a/docs/src/content/examples/select-one-or-more-from-a-list-of-options/angular.html b/docs/src/content/examples/select-one-or-more-from-a-list-of-options/angular.html
new file mode 100644
index 0000000000..98979cdfaf
--- /dev/null
+++ b/docs/src/content/examples/select-one-or-more-from-a-list-of-options/angular.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
diff --git a/docs/src/content/examples/select-one-or-more-from-a-list-of-options/angular.ts b/docs/src/content/examples/select-one-or-more-from-a-list-of-options/angular.ts
new file mode 100644
index 0000000000..1151e5def5
--- /dev/null
+++ b/docs/src/content/examples/select-one-or-more-from-a-list-of-options/angular.ts
@@ -0,0 +1,13 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-select-one-or-more-from-a-list-of-options",
+ templateUrl: "./angular.html",
+})
+export class SelectOneOrMoreFromAListOfOptionsComponent {
+ selectedOptions: string[] = [];
+
+ onSelectionChange(event: { detail: { value: string[] } }): void {
+ this.selectedOptions = event.detail.value;
+ }
+}
diff --git a/docs/src/content/examples/select-one-or-more-from-a-list-of-options/index.mdx b/docs/src/content/examples/select-one-or-more-from-a-list-of-options/index.mdx
new file mode 100644
index 0000000000..ae7eb3cec5
--- /dev/null
+++ b/docs/src/content/examples/select-one-or-more-from-a-list-of-options/index.mdx
@@ -0,0 +1,35 @@
+---
+id: select-one-or-more-from-a-list-of-options
+title: Select one or more from a list of options
+categories:
+ - forms
+scale: task
+userType: both
+tags:
+ - checkbox
+ - selection
+ - multiple
+ - form
+components:
+ - checkbox
+ - form-item
+status: published
+---
+
+Use checkboxes to let users select one or more options from a list when multiple selections are valid.
+
+## When to use
+
+Use this pattern when:
+- Users can select multiple options from a predefined list
+- All options that apply should be selected
+- The list of options is relatively short (up to ~7 items)
+- Each option is independent of the others
+
+## Considerations
+
+- Use clear, concise labels for each option
+- Include help text like "Choose all that apply" to indicate multiple selection
+- Consider the order of options (most common first, alphabetical, etc.)
+- For longer lists, consider a different component like multi-select dropdown
+- Ensure adequate touch targets for mobile users
diff --git a/docs/src/content/examples/select-one-or-more-from-a-list-of-options/react.tsx b/docs/src/content/examples/select-one-or-more-from-a-list-of-options/react.tsx
new file mode 100644
index 0000000000..12d7b75550
--- /dev/null
+++ b/docs/src/content/examples/select-one-or-more-from-a-list-of-options/react.tsx
@@ -0,0 +1,23 @@
+import { useState } from "react";
+import { GoabCheckbox, GoabCheckboxList, GoabFormItem } from "@abgov/react-components";
+
+export function SelectOneOrMoreFromAListOfOptions() {
+ const [selectedOptions, setSelectedOptions] = useState([]);
+
+ return (
+
+ setSelectedOptions(e.detail.value)}
+ >
+
+
+
+
+
+ );
+}
diff --git a/docs/src/content/examples/select-one-or-more-from-a-list-of-options/web-components.html b/docs/src/content/examples/select-one-or-more-from-a-list-of-options/web-components.html
new file mode 100644
index 0000000000..eed1a096d3
--- /dev/null
+++ b/docs/src/content/examples/select-one-or-more-from-a-list-of-options/web-components.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/examples/set-a-max-width-on-a-long-radio-item/angular.html b/docs/src/content/examples/set-a-max-width-on-a-long-radio-item/angular.html
new file mode 100644
index 0000000000..fb1d2080d9
--- /dev/null
+++ b/docs/src/content/examples/set-a-max-width-on-a-long-radio-item/angular.html
@@ -0,0 +1,16 @@
+
diff --git a/docs/src/content/examples/set-a-max-width-on-a-long-radio-item/angular.ts b/docs/src/content/examples/set-a-max-width-on-a-long-radio-item/angular.ts
new file mode 100644
index 0000000000..cd9fbf665f
--- /dev/null
+++ b/docs/src/content/examples/set-a-max-width-on-a-long-radio-item/angular.ts
@@ -0,0 +1,14 @@
+import { Component } from "@angular/core";
+import { GoabRadioGroupOnChangeDetail } from "@abgov/ui-components-common";
+
+@Component({
+ selector: "app-set-a-max-width-on-a-long-radio-item",
+ templateUrl: "./angular.html"
+})
+export class SetAMaxWidthOnALongRadioItemComponent {
+ selectOne = "1";
+
+ onRadioChange(event: GoabRadioGroupOnChangeDetail): void {
+ this.selectOne = event.value;
+ }
+}
diff --git a/docs/src/content/examples/set-a-max-width-on-a-long-radio-item/index.mdx b/docs/src/content/examples/set-a-max-width-on-a-long-radio-item/index.mdx
new file mode 100644
index 0000000000..c1fc03b9c8
--- /dev/null
+++ b/docs/src/content/examples/set-a-max-width-on-a-long-radio-item/index.mdx
@@ -0,0 +1,33 @@
+---
+id: set-a-max-width-on-a-long-radio-item
+title: Set a max width on a long radio item
+categories:
+ - inputs-and-actions
+scale: interaction
+userType: both
+tags:
+ - radio
+ - forms
+ - layout
+components:
+ - form-item
+ - radio-group
+ - radio-item
+status: published
+---
+
+Set a max width on a long radio item to control line wrapping.
+
+## When to use
+
+Use this pattern when:
+- You have radio options with long labels that need width control
+- You want to prevent radio items from becoming too wide on large screens
+- You need consistent radio item sizing across different viewport sizes
+
+## Considerations
+
+- The `maxWidth` property accepts CSS width values like "300px" or "20ch"
+- Consider the reading experience when setting max widths
+- Ensure the max width still allows for readable label text
+- Use consistent max widths across similar form elements for visual harmony
diff --git a/docs/src/content/examples/set-a-max-width-on-a-long-radio-item/react.tsx b/docs/src/content/examples/set-a-max-width-on-a-long-radio-item/react.tsx
new file mode 100644
index 0000000000..2c91bf5da2
--- /dev/null
+++ b/docs/src/content/examples/set-a-max-width-on-a-long-radio-item/react.tsx
@@ -0,0 +1,30 @@
+import { useState } from "react";
+import {
+ GoabFormItem,
+ GoabRadioGroup,
+ GoabRadioItem
+} from "@abgov/react-components";
+import { GoabRadioGroupOnChangeDetail } from "@abgov/ui-components-common";
+
+export function SetAMaxWidthOnALongRadioItem() {
+ const [selectOne, setSelectOne] = useState("1");
+
+ return (
+
+ );
+}
diff --git a/docs/src/content/examples/set-a-max-width-on-a-long-radio-item/web-components.html b/docs/src/content/examples/set-a-max-width-on-a-long-radio-item/web-components.html
new file mode 100644
index 0000000000..811ca7bd52
--- /dev/null
+++ b/docs/src/content/examples/set-a-max-width-on-a-long-radio-item/web-components.html
@@ -0,0 +1,19 @@
+
+
+
diff --git a/docs/src/content/examples/set-a-specific-tab-to-be-active/angular.html b/docs/src/content/examples/set-a-specific-tab-to-be-active/angular.html
new file mode 100644
index 0000000000..aeac52e5a2
--- /dev/null
+++ b/docs/src/content/examples/set-a-specific-tab-to-be-active/angular.html
@@ -0,0 +1,86 @@
+
+
+
+
+
+
Status
+
Text
+
Number
+
Action
+
+
+
+
+
+
+
+
Lorem Ipsum
+
1234567890
+
+ Action
+
+
+
+
+
+
+
Lorem Ipsum
+
1234567890
+
+ Action
+
+
+
+
+
+
+ Review pending
+
+
+
+
Status
+
Text
+
Number
+
Action
+
+
+
+
+
+
+
+
Lorem Ipsum
+
1234567890
+
+ Action
+
+
+
+
+
+
+ Complete
+
+
+
+
Status
+
Text
+
Number
+
Action
+
+
+
+
+
+
+
+
Lorem Ipsum
+
1234567890
+
+ Action
+
+
+
+
+
+
diff --git a/docs/src/content/examples/set-a-specific-tab-to-be-active/angular.ts b/docs/src/content/examples/set-a-specific-tab-to-be-active/angular.ts
new file mode 100644
index 0000000000..e3227285b0
--- /dev/null
+++ b/docs/src/content/examples/set-a-specific-tab-to-be-active/angular.ts
@@ -0,0 +1,10 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-set-a-specific-tab-to-be-active",
+ templateUrl: "./angular.html"
+})
+export class SetASpecificTabToBeActiveComponent {
+ review = [0, 1, 2, 3];
+ complete = [0, 1];
+}
diff --git a/docs/src/content/examples/set-a-specific-tab-to-be-active/index.mdx b/docs/src/content/examples/set-a-specific-tab-to-be-active/index.mdx
new file mode 100644
index 0000000000..797115b3a2
--- /dev/null
+++ b/docs/src/content/examples/set-a-specific-tab-to-be-active/index.mdx
@@ -0,0 +1,36 @@
+---
+id: set-a-specific-tab-to-be-active
+title: Set a specific tab to be active
+categories:
+ - inputs-and-actions
+scale: interaction
+userType: both
+tags:
+ - tabs
+ - navigation
+ - tables
+components:
+ - tabs
+ - tab
+ - table
+ - badge
+ - button
+status: published
+---
+
+Set a specific tab to be active on page load using the initialTab property.
+
+## When to use
+
+Use this pattern when:
+- You want to load a specific tab as the default active tab
+- Users should start viewing a particular tab based on context
+- Deep linking to specific tab content is required
+- Showing priority content like items requiring attention
+
+## Considerations
+
+- The `initialTab` property uses zero-based indexing (0 = first tab, 1 = second tab, etc.)
+- Consider which tab provides the most relevant content for users on initial load
+- Badge counts in tab headings help users understand the volume of items in each tab
+- Ensure tab content is accessible and keyboard navigable
diff --git a/docs/src/content/examples/set-a-specific-tab-to-be-active/react.tsx b/docs/src/content/examples/set-a-specific-tab-to-be-active/react.tsx
new file mode 100644
index 0000000000..dc63af3d39
--- /dev/null
+++ b/docs/src/content/examples/set-a-specific-tab-to-be-active/react.tsx
@@ -0,0 +1,107 @@
+import {
+ GoabBadge,
+ GoabButton,
+ GoabTab,
+ GoabTable,
+ GoabTabs,
+} from "@abgov/react-components";
+
+export function SetASpecificTabToBeActive() {
+ const review = [0, 1, 2, 3];
+ const complete = [0, 1];
+
+ return (
+
+
+
+
+
diff --git a/docs/src/content/examples/set-the-status-of-step-on-a-form-stepper/angular.ts b/docs/src/content/examples/set-the-status-of-step-on-a-form-stepper/angular.ts
new file mode 100644
index 0000000000..8d203f4be8
--- /dev/null
+++ b/docs/src/content/examples/set-the-status-of-step-on-a-form-stepper/angular.ts
@@ -0,0 +1,20 @@
+import { Component } from "@angular/core";
+import { GoabFormStepperOnChangeDetail, GoabFormStepStatus } from "@abgov/ui-components-common";
+
+@Component({
+ selector: "app-set-the-status-of-step-on-a-form-stepper",
+ templateUrl: "./angular.html"
+})
+export class SetTheStatusOfStepOnAFormStepperComponent {
+ step = -1;
+ status: GoabFormStepStatus[] = ["complete", "complete", "incomplete", "not-started"];
+
+ updateStep(event: GoabFormStepperOnChangeDetail): void {
+ this.step = event.step;
+ }
+
+ setPage(page: number): void {
+ if (page < 1 || page > 4) return;
+ this.step = page;
+ }
+}
diff --git a/docs/src/content/examples/set-the-status-of-step-on-a-form-stepper/index.mdx b/docs/src/content/examples/set-the-status-of-step-on-a-form-stepper/index.mdx
new file mode 100644
index 0000000000..130ce7b5e3
--- /dev/null
+++ b/docs/src/content/examples/set-the-status-of-step-on-a-form-stepper/index.mdx
@@ -0,0 +1,37 @@
+---
+id: set-the-status-of-step-on-a-form-stepper
+title: Set the status of step on a form stepper
+categories:
+ - inputs-and-actions
+scale: task
+userType: both
+tags:
+ - forms
+ - stepper
+ - multi-step
+ - navigation
+components:
+ - form-stepper
+ - form-step
+ - pages
+ - button
+status: published
+---
+
+Set the status of each step on a form stepper to indicate completion progress.
+
+## When to use
+
+Use this pattern when:
+- Building multi-step forms that need visual progress indication
+- Users need to see which steps are complete, incomplete, or not started
+- You want to provide clear navigation through a complex form process
+- Form completion status needs to be tracked and displayed
+
+## Considerations
+
+- The status property accepts "complete", "incomplete", or "not-started" values
+- Status is controlled by the application based on form completion
+- Consider updating step status as users complete each section
+- Provide clear Previous/Next navigation to move between steps
+- The form stepper can be clicked to navigate directly to completed steps
diff --git a/docs/src/content/examples/set-the-status-of-step-on-a-form-stepper/react.tsx b/docs/src/content/examples/set-the-status-of-step-on-a-form-stepper/react.tsx
new file mode 100644
index 0000000000..95413e7ec9
--- /dev/null
+++ b/docs/src/content/examples/set-the-status-of-step-on-a-form-stepper/react.tsx
@@ -0,0 +1,66 @@
+import { useState } from "react";
+import {
+ GoabButton,
+ GoabFormStep,
+ GoabFormStepper,
+ GoabPages,
+ GoabSkeleton,
+ GoabSpacer
+} from "@abgov/react-components";
+import { GoabFormStepStatus } from "@abgov/ui-components-common";
+
+export function SetTheStatusOfStepOnAFormStepper() {
+ const [step, setStep] = useState(-1);
+ const status: GoabFormStepStatus[] = [
+ "complete",
+ "complete",
+ "incomplete",
+ "not-started"
+ ];
+
+ function setPage(page: number) {
+ if (page < 1 || page > 4) return;
+ setStep(page);
+ }
+
+ return (
+ <>
+ setStep(event.step)}>
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/examples/show-a-label-on-an-icon-only-button/angular.html b/docs/src/content/examples/show-a-label-on-an-icon-only-button/angular.html
new file mode 100644
index 0000000000..1bc72afeae
--- /dev/null
+++ b/docs/src/content/examples/show-a-label-on-an-icon-only-button/angular.html
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/examples/show-a-label-on-an-icon-only-button/angular.ts b/docs/src/content/examples/show-a-label-on-an-icon-only-button/angular.ts
new file mode 100644
index 0000000000..25bc5996c0
--- /dev/null
+++ b/docs/src/content/examples/show-a-label-on-an-icon-only-button/angular.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-show-a-label-on-an-icon-only-button",
+ templateUrl: "./angular.html"
+})
+export class ShowALabelOnAnIconOnlyButtonComponent {}
diff --git a/docs/src/content/examples/show-a-label-on-an-icon-only-button/index.mdx b/docs/src/content/examples/show-a-label-on-an-icon-only-button/index.mdx
new file mode 100644
index 0000000000..159b769a4e
--- /dev/null
+++ b/docs/src/content/examples/show-a-label-on-an-icon-only-button/index.mdx
@@ -0,0 +1,36 @@
+---
+id: show-a-label-on-an-icon-only-button
+title: Show a label on an icon only button
+categories:
+ - inputs-and-actions
+scale: interaction
+userType: both
+tags:
+ - buttons
+ - icons
+ - accessibility
+ - tooltip
+components:
+ - icon-button
+ - tooltip
+ - button-group
+status: published
+---
+
+Show a label on an icon-only button using a tooltip to improve discoverability.
+
+## When to use
+
+Use this pattern when:
+- Using icon buttons without visible text labels
+- Users might not recognize what an icon means
+- You want to provide context for icon-only actions
+- Building toolbars or action bars with multiple icon buttons
+
+## Considerations
+
+- Always include an `ariaLabel` on icon buttons for screen reader accessibility
+- Tooltips provide visual context but should not be the only way to understand the action
+- Keep tooltip content short and descriptive
+- Group related icon buttons together using a button group
+- Consider using text labels instead of tooltips for critical actions
diff --git a/docs/src/content/examples/show-a-label-on-an-icon-only-button/react.tsx b/docs/src/content/examples/show-a-label-on-an-icon-only-button/react.tsx
new file mode 100644
index 0000000000..f2eb95fc00
--- /dev/null
+++ b/docs/src/content/examples/show-a-label-on-an-icon-only-button/react.tsx
@@ -0,0 +1,21 @@
+import {
+ GoabButtonGroup,
+ GoabIconButton,
+ GoabTooltip
+} from "@abgov/react-components";
+
+export function ShowALabelOnAnIconOnlyButton() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/docs/src/content/examples/show-a-label-on-an-icon-only-button/web-components.html b/docs/src/content/examples/show-a-label-on-an-icon-only-button/web-components.html
new file mode 100644
index 0000000000..52e44f49ae
--- /dev/null
+++ b/docs/src/content/examples/show-a-label-on-an-icon-only-button/web-components.html
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/examples/show-a-list-to-help-answer-a-question/angular.html b/docs/src/content/examples/show-a-list-to-help-answer-a-question/angular.html
new file mode 100644
index 0000000000..322b4e71a1
--- /dev/null
+++ b/docs/src/content/examples/show-a-list-to-help-answer-a-question/angular.html
@@ -0,0 +1,35 @@
+
diff --git a/docs/src/content/examples/show-a-list-to-help-answer-a-question/angular.ts b/docs/src/content/examples/show-a-list-to-help-answer-a-question/angular.ts
new file mode 100644
index 0000000000..0173fe1a0c
--- /dev/null
+++ b/docs/src/content/examples/show-a-list-to-help-answer-a-question/angular.ts
@@ -0,0 +1,21 @@
+import { Component } from "@angular/core";
+import { FormBuilder, FormGroup } from "@angular/forms";
+
+@Component({
+ selector: "app-show-a-list-to-help-answer-a-question",
+ templateUrl: "./angular.html"
+})
+export class ShowAListToHelpAnswerAQuestionComponent {
+ form: FormGroup;
+
+ constructor(private fb: FormBuilder) {
+ this.form = this.fb.group({
+ additional: [""]
+ });
+ }
+
+ onRadioChange(event: Event): void {
+ const detail = (event as CustomEvent).detail;
+ console.log("value is", detail.value);
+ }
+}
diff --git a/docs/src/content/examples/show-a-list-to-help-answer-a-question/index.mdx b/docs/src/content/examples/show-a-list-to-help-answer-a-question/index.mdx
new file mode 100644
index 0000000000..fc996f0a91
--- /dev/null
+++ b/docs/src/content/examples/show-a-list-to-help-answer-a-question/index.mdx
@@ -0,0 +1,38 @@
+---
+id: show-a-list-to-help-answer-a-question
+title: Show a list to help answer a question
+categories:
+ - forms
+scale: task
+userType: citizen
+tags:
+ - forms
+ - details
+ - guidance
+ - help
+components:
+ - form-item
+ - radio-group
+ - radio-item
+ - details
+ - block
+status: published
+---
+
+Show a list to help answer a question using an expandable details component.
+
+## When to use
+
+Use this pattern when:
+- Users need clarification about what items qualify for a question
+- You want to provide examples of what to include or exclude
+- The guidance content would clutter the form if always visible
+- Users can make better decisions with reference information
+
+## Considerations
+
+- Place the details component after the form question it relates to
+- Use clear headings within the details to organize content
+- Include both "examples of" and "do not include" lists when relevant
+- Keep the details heading phrased as a question to indicate it provides clarification
+- Ensure the expanded content is easy to scan with clear formatting
diff --git a/docs/src/content/examples/show-a-list-to-help-answer-a-question/react.tsx b/docs/src/content/examples/show-a-list-to-help-answer-a-question/react.tsx
new file mode 100644
index 0000000000..9e1fc5ebab
--- /dev/null
+++ b/docs/src/content/examples/show-a-list-to-help-answer-a-question/react.tsx
@@ -0,0 +1,52 @@
+import {
+ GoabBlock,
+ GoabDetails,
+ GoabFormItem,
+ GoabRadioGroup,
+ GoabRadioItem
+} from "@abgov/react-components";
+import { GoabRadioGroupOnChangeDetail } from "@abgov/ui-components-common";
+
+export function ShowAListToHelpAnswerAQuestion() {
+ const handleChange = (event: GoabRadioGroupOnChangeDetail) => {
+ console.log("value is", event.value);
+ };
+
+ return (
+
+ );
+}
diff --git a/docs/src/content/examples/show-a-list-to-help-answer-a-question/web-components.html b/docs/src/content/examples/show-a-list-to-help-answer-a-question/web-components.html
new file mode 100644
index 0000000000..f6dde5df05
--- /dev/null
+++ b/docs/src/content/examples/show-a-list-to-help-answer-a-question/web-components.html
@@ -0,0 +1,41 @@
+
+
+
diff --git a/docs/src/content/examples/show-a-notification-with-an-action/angular.html b/docs/src/content/examples/show-a-notification-with-an-action/angular.html
new file mode 100644
index 0000000000..4715918400
--- /dev/null
+++ b/docs/src/content/examples/show-a-notification-with-an-action/angular.html
@@ -0,0 +1,3 @@
+
+
+Comment
diff --git a/docs/src/content/examples/show-a-notification-with-an-action/angular.ts b/docs/src/content/examples/show-a-notification-with-an-action/angular.ts
new file mode 100644
index 0000000000..9bb596ae0b
--- /dev/null
+++ b/docs/src/content/examples/show-a-notification-with-an-action/angular.ts
@@ -0,0 +1,20 @@
+import { Component } from "@angular/core";
+import { TemporaryNotification } from "@abgov/ui-components-common";
+
+@Component({
+ selector: "app-show-a-notification-with-an-action",
+ templateUrl: "./angular.html"
+})
+export class ShowANotificationWithAnActionComponent {
+ comment(): void {
+ const uuid = TemporaryNotification.show(
+ "Edna Mode commented on your assigned case.",
+ {
+ actionText: "View",
+ action: () => {
+ TemporaryNotification.dismiss(uuid);
+ }
+ }
+ );
+ }
+}
diff --git a/docs/src/content/examples/show-a-notification-with-an-action/index.mdx b/docs/src/content/examples/show-a-notification-with-an-action/index.mdx
new file mode 100644
index 0000000000..67cf083b67
--- /dev/null
+++ b/docs/src/content/examples/show-a-notification-with-an-action/index.mdx
@@ -0,0 +1,35 @@
+---
+id: show-a-notification-with-an-action
+title: Show a notification with an action
+categories:
+ - feedback-and-alerts
+scale: interaction
+userType: both
+tags:
+ - notification
+ - feedback
+ - action
+ - toast
+components:
+ - temporary-notification
+ - button
+status: published
+---
+
+Show a temporary notification with an action button for user interaction.
+
+## When to use
+
+Use this pattern when:
+- Users need to take action in response to a notification
+- Providing a quick way to navigate to related content
+- Showing activity notifications that users may want to respond to
+- The action should dismiss the notification when clicked
+
+## Considerations
+
+- Use `actionText` to set the button label in the notification
+- The `action` callback receives the notification UUID for dismissal
+- Use `TemporaryNotification.dismiss(uuid)` to close the notification programmatically
+- Keep action text short and clear (e.g., "View", "Undo", "Open")
+- Consider what happens if the user doesn't click the action before auto-dismiss
diff --git a/docs/src/content/examples/show-a-notification-with-an-action/react.tsx b/docs/src/content/examples/show-a-notification-with-an-action/react.tsx
new file mode 100644
index 0000000000..aea2ff62c7
--- /dev/null
+++ b/docs/src/content/examples/show-a-notification-with-an-action/react.tsx
@@ -0,0 +1,23 @@
+import { GoabButton, GoabTemporaryNotificationCtrl } from "@abgov/react-components";
+import { TemporaryNotification } from "@abgov/ui-components-common";
+
+export function ShowANotificationWithAnAction() {
+ const comment = () => {
+ const uuid = TemporaryNotification.show(
+ "Edna Mode commented on your assigned case.",
+ {
+ actionText: "View",
+ action: () => {
+ TemporaryNotification.dismiss(uuid);
+ }
+ }
+ );
+ };
+
+ return (
+ <>
+
+ Comment
+ >
+ );
+}
diff --git a/docs/src/content/examples/show-a-notification-with-an-action/web-components.html b/docs/src/content/examples/show-a-notification-with-an-action/web-components.html
new file mode 100644
index 0000000000..7a0bc7af83
--- /dev/null
+++ b/docs/src/content/examples/show-a-notification-with-an-action/web-components.html
@@ -0,0 +1,44 @@
+
+
+Comment
+
+
diff --git a/docs/src/content/examples/show-a-notification/angular.html b/docs/src/content/examples/show-a-notification/angular.html
new file mode 100644
index 0000000000..0cc437abd2
--- /dev/null
+++ b/docs/src/content/examples/show-a-notification/angular.html
@@ -0,0 +1,3 @@
+
+
+Save
diff --git a/docs/src/content/examples/show-a-notification/angular.ts b/docs/src/content/examples/show-a-notification/angular.ts
new file mode 100644
index 0000000000..482077f550
--- /dev/null
+++ b/docs/src/content/examples/show-a-notification/angular.ts
@@ -0,0 +1,16 @@
+import { Component } from "@angular/core";
+import { TemporaryNotification } from "@abgov/ui-components-common";
+
+@Component({
+ selector: "app-show-a-notification",
+ templateUrl: "./angular.html"
+})
+export class ShowANotificationComponent {
+ async save(): Promise {
+ // await this.api.save();
+
+ TemporaryNotification.show("Your application has been saved.", {
+ type: "success"
+ });
+ }
+}
diff --git a/docs/src/content/examples/show-a-notification/index.mdx b/docs/src/content/examples/show-a-notification/index.mdx
new file mode 100644
index 0000000000..765a4c4713
--- /dev/null
+++ b/docs/src/content/examples/show-a-notification/index.mdx
@@ -0,0 +1,35 @@
+---
+id: show-a-notification
+title: Show a notification
+categories:
+ - feedback-and-alerts
+scale: interaction
+userType: both
+tags:
+ - notification
+ - feedback
+ - success
+ - toast
+components:
+ - temporary-notification
+ - button
+status: published
+---
+
+Show a temporary notification to confirm an action was completed successfully.
+
+## When to use
+
+Use this pattern when:
+- Confirming that a save operation completed successfully
+- Providing immediate feedback after a user action
+- The notification should automatically dismiss after a few seconds
+- Users need non-intrusive confirmation of their action
+
+## Considerations
+
+- Use the `type` option to indicate the nature of the notification (success, information, etc.)
+- Import `TemporaryNotification` from `@abgov/ui-components-common`
+- Include a `` component in your app to render notifications
+- Keep notification messages concise and action-oriented
+- Notifications auto-dismiss after a default duration
diff --git a/docs/src/content/examples/show-a-notification/react.tsx b/docs/src/content/examples/show-a-notification/react.tsx
new file mode 100644
index 0000000000..6d0b892295
--- /dev/null
+++ b/docs/src/content/examples/show-a-notification/react.tsx
@@ -0,0 +1,19 @@
+import { GoabButton, GoabTemporaryNotificationCtrl } from "@abgov/react-components";
+import { TemporaryNotification } from "@abgov/ui-components-common";
+
+export function ShowANotification() {
+ const save = async () => {
+ // await api.save();
+
+ TemporaryNotification.show("Your application has been saved.", {
+ type: "success"
+ });
+ };
+
+ return (
+ <>
+
+ Save
+ >
+ );
+}
diff --git a/docs/src/content/examples/show-a-notification/web-components.html b/docs/src/content/examples/show-a-notification/web-components.html
new file mode 100644
index 0000000000..68ef07298c
--- /dev/null
+++ b/docs/src/content/examples/show-a-notification/web-components.html
@@ -0,0 +1,23 @@
+
+
+Save
+
+
diff --git a/docs/src/content/examples/show-a-section-title-on-a-question-page/angular.html b/docs/src/content/examples/show-a-section-title-on-a-question-page/angular.html
new file mode 100644
index 0000000000..3d3b60c7e9
--- /dev/null
+++ b/docs/src/content/examples/show-a-section-title-on-a-question-page/angular.html
@@ -0,0 +1,19 @@
+
+ Back
+
+
+Personal information
+
+
+
+
+
+
+
+
+
+ Save and continue
+
diff --git a/docs/src/content/examples/show-a-section-title-on-a-question-page/angular.ts b/docs/src/content/examples/show-a-section-title-on-a-question-page/angular.ts
new file mode 100644
index 0000000000..a890477c10
--- /dev/null
+++ b/docs/src/content/examples/show-a-section-title-on-a-question-page/angular.ts
@@ -0,0 +1,40 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-show-a-section-title-on-a-question-page",
+ templateUrl: "./angular.html",
+ styles: [`
+ a.back-link::before {
+ content: "";
+ display: inline-block;
+ width: 42px;
+ height: 24px;
+ vertical-align: middle;
+ background: url('data:image/svg+xml,') center center no-repeat;
+ }
+
+ a.back-link:visited::before,
+ a.back-link:hover::before {
+ background: url('data:image/svg+xml,') center center no-repeat;
+ }
+
+ a.back-link {
+ margin-top: var(--goa-space-m);
+ }
+
+ h3.section-title {
+ margin-bottom: 0;
+ color: var(--goa-color-text-secondary);
+ }
+
+ a.back-link + h3 {
+ margin-top: var(--goa-space-2xl);
+ }
+ `]
+})
+export class ShowASectionTitleOnAQuestionPageComponent {
+ onRadioChange(event: Event): void {
+ const detail = (event as CustomEvent).detail;
+ console.log("Selected:", detail.value);
+ }
+}
diff --git a/docs/src/content/examples/show-a-section-title-on-a-question-page/index.mdx b/docs/src/content/examples/show-a-section-title-on-a-question-page/index.mdx
new file mode 100644
index 0000000000..9bf4818b4b
--- /dev/null
+++ b/docs/src/content/examples/show-a-section-title-on-a-question-page/index.mdx
@@ -0,0 +1,37 @@
+---
+id: show-a-section-title-on-a-question-page
+title: Show a section title on a question page
+categories:
+ - forms
+scale: task
+userType: citizen
+tags:
+ - forms
+ - questions
+ - navigation
+ - section
+components:
+ - form-item
+ - radio-group
+ - radio-item
+ - button
+status: published
+---
+
+Show a section title on a question page to help users understand which part of the form they are completing.
+
+## When to use
+
+Use this pattern when:
+- Building multi-section forms where context helps users
+- Users need to know which category of questions they are answering
+- The form is divided into logical sections like "Personal information"
+- Following the one-question-per-page pattern for government services
+
+## Considerations
+
+- Use a subdued text color for the section title to differentiate from the question
+- Include a back link for navigation to previous questions
+- The section title should appear above the question
+- Use consistent spacing between the back link, section title, and question
+- Keep section titles concise and descriptive
diff --git a/docs/src/content/examples/show-a-section-title-on-a-question-page/react.tsx b/docs/src/content/examples/show-a-section-title-on-a-question-page/react.tsx
new file mode 100644
index 0000000000..b9d7817214
--- /dev/null
+++ b/docs/src/content/examples/show-a-section-title-on-a-question-page/react.tsx
@@ -0,0 +1,34 @@
+import {
+ GoabButton,
+ GoabFormItem,
+ GoabLink,
+ GoabRadioGroup,
+ GoabRadioItem,
+ GoabText
+} from "@abgov/react-components";
+
+export function ShowASectionTitleOnAQuestionPage() {
+ return (
+ <>
+
+ Back
+
+
+ Personal information
+
+
+ {}}>
+
+
+
+
+
+
+ Save and continue
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/show-a-section-title-on-a-question-page/web-components.html b/docs/src/content/examples/show-a-section-title-on-a-question-page/web-components.html
new file mode 100644
index 0000000000..bebcddabdd
--- /dev/null
+++ b/docs/src/content/examples/show-a-section-title-on-a-question-page/web-components.html
@@ -0,0 +1,22 @@
+
+ Back
+
+
+Personal information
+
+
+
+
+
+
+
+
+
+ Save and continue
+
+
+
diff --git a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/angular.html b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/angular.html
new file mode 100644
index 0000000000..e37b8a6085
--- /dev/null
+++ b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/angular.html
@@ -0,0 +1,24 @@
+
+ Back
+
+
+Step 1 of 5
+Personal information
+
+
+
+
+
+
+
+
+1
+
+
+
+
+
+
+
+
+ Save and continue
+
diff --git a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/angular.ts b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/angular.ts
new file mode 100644
index 0000000000..6c5af2d074
--- /dev/null
+++ b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/angular.ts
@@ -0,0 +1,44 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions",
+ templateUrl: "./angular.html",
+ styles: [`
+ a.back-link::before {
+ content: "";
+ display: inline-block;
+ width: 42px;
+ height: 24px;
+ vertical-align: middle;
+ background: url('data:image/svg+xml,') center center no-repeat;
+ }
+
+ a.back-link:visited::before,
+ a.back-link:hover::before {
+ background: url('data:image/svg+xml,') center center no-repeat;
+ }
+
+ a.back-link {
+ margin-top: var(--goa-space-m);
+ }
+
+ h3.section-title {
+ margin-bottom: 0;
+ color: var(--goa-color-text-secondary);
+ }
+
+ a.back-link + h3 {
+ margin-top: var(--goa-space-2xl);
+ }
+
+ h3.section-title + h2 {
+ margin-top: var(--goa-space-xs);
+ }
+ `]
+})
+export class ShowASimpleProgressIndicatorOnAQuestionPageWithMultipleQuestionsComponent {
+ onChange(event: Event): void {
+ const detail = (event as CustomEvent).detail;
+ console.log("Value:", detail.value);
+ }
+}
diff --git a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/index.mdx b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/index.mdx
new file mode 100644
index 0000000000..aeb7b3892a
--- /dev/null
+++ b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/index.mdx
@@ -0,0 +1,38 @@
+---
+id: show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions
+title: Show a simple progress indicator on a question page with multiple questions
+categories:
+ - forms
+scale: task
+userType: citizen
+tags:
+ - forms
+ - questions
+ - progress
+ - navigation
+ - multi-question
+components:
+ - form-item
+ - input
+ - button
+status: published
+---
+
+Show a simple progress indicator on a question page when grouping multiple related questions together.
+
+## When to use
+
+Use this pattern when:
+- Grouping multiple related questions on a single page improves the user experience
+- The questions form a logical unit (e.g., personal information fields)
+- Users benefit from progress tracking across the form
+- A step-based indicator shows progress through form sections
+
+## Considerations
+
+- Display progress as "Step X of Y" when grouping questions into sections
+- Include a clear section heading that describes the group of questions
+- Use a subdued text color for the progress indicator
+- Include a back link for navigation to previous sections
+- Position related questions close together with consistent spacing
+- The `leadingContent` prop on inputs can add prefixes like country codes
diff --git a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/react.tsx b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/react.tsx
new file mode 100644
index 0000000000..bb0ba75740
--- /dev/null
+++ b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/react.tsx
@@ -0,0 +1,46 @@
+import {
+ GoabButton,
+ GoabFormItem,
+ GoabInput,
+ GoabLink,
+ GoabText
+} from "@abgov/react-components";
+
+export function ShowASimpleProgressIndicatorOnAQuestionPageWithMultipleQuestions() {
+ return (
+ <>
+
+ Back
+
+
+ Step 1 of 5
+ Personal information
+
+
+ {}} name="name" ariaLabel="what is your name?" width="50ch" />
+
+
+
+ {}}
+ name="phone-number"
+ ariaLabel="what is your phone number?"
+ leadingContent="+1"
+ />
+
+
+
+ {}}
+ name="postal-code"
+ width="14ch"
+ ariaLabel="what is your home postal code"
+ />
+
+
+
+ Save and continue
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/web-components.html b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/web-components.html
new file mode 100644
index 0000000000..c95d48d76f
--- /dev/null
+++ b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/web-components.html
@@ -0,0 +1,32 @@
+
+ Back
+
+
+Step 1 of 5
+Personal information
+
+
+
+
+
+
+
+
+1
+
+
+
+
+
+
+
+
+ Save and continue
+
+
+
diff --git a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/angular.html b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/angular.html
new file mode 100644
index 0000000000..94ef1ebabf
--- /dev/null
+++ b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/angular.html
@@ -0,0 +1,19 @@
+
+ Back
+
+
+Question 3 of 9
+
+
+
+
+
+
+
+
+
+ Save and continue
+
diff --git a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/angular.ts b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/angular.ts
new file mode 100644
index 0000000000..aa96c9e6ea
--- /dev/null
+++ b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/angular.ts
@@ -0,0 +1,40 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-show-a-simple-progress-indicator-on-a-question-page",
+ templateUrl: "./angular.html",
+ styles: [`
+ h3.section-title {
+ margin-bottom: 0;
+ color: var(--goa-color-text-secondary);
+ }
+
+ a.back-link::before {
+ content: "";
+ display: inline-block;
+ width: 42px;
+ height: 24px;
+ vertical-align: middle;
+ background: url('data:image/svg+xml,') center center no-repeat;
+ }
+
+ a.back-link:visited::before,
+ a.back-link:hover::before {
+ background: url('data:image/svg+xml,') center center no-repeat;
+ }
+
+ a.back-link {
+ margin-top: var(--goa-space-m);
+ }
+
+ a.back-link + h3 {
+ margin-top: var(--goa-space-2xl);
+ }
+ `]
+})
+export class ShowASimpleProgressIndicatorOnAQuestionPageComponent {
+ onRadioChange(event: Event): void {
+ const detail = (event as CustomEvent).detail;
+ console.log("Selected:", detail.value);
+ }
+}
diff --git a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/index.mdx b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/index.mdx
new file mode 100644
index 0000000000..4bbd732031
--- /dev/null
+++ b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/index.mdx
@@ -0,0 +1,37 @@
+---
+id: show-a-simple-progress-indicator-on-a-question-page
+title: Show a simple progress indicator on a question page
+categories:
+ - forms
+scale: task
+userType: citizen
+tags:
+ - forms
+ - questions
+ - progress
+ - navigation
+components:
+ - form-item
+ - radio-group
+ - radio-item
+ - button
+status: published
+---
+
+Show a simple progress indicator on a question page to help users understand their progress through the form.
+
+## When to use
+
+Use this pattern when:
+- Building a multi-question form where progress tracking helps users
+- Users benefit from knowing how many questions remain
+- The form has a linear flow with a known number of questions
+- Following the one-question-per-page pattern for government services
+
+## Considerations
+
+- Display progress as "Question X of Y" for clarity
+- Use a subdued text color for the progress indicator
+- Include a back link for navigation to previous questions
+- Position the progress indicator above the question
+- Keep the format consistent throughout the form
diff --git a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/react.tsx b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/react.tsx
new file mode 100644
index 0000000000..56967a365f
--- /dev/null
+++ b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/react.tsx
@@ -0,0 +1,34 @@
+import {
+ GoabButton,
+ GoabFormItem,
+ GoabLink,
+ GoabRadioGroup,
+ GoabRadioItem,
+ GoabText
+} from "@abgov/react-components";
+
+export function ShowASimpleProgressIndicatorOnAQuestionPage() {
+ return (
+ <>
+
+ Back
+
+
+ Question 3 of 9
+
+
+ {}}>
+
+
+
+
+
+
+ Save and continue
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/web-components.html b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/web-components.html
new file mode 100644
index 0000000000..3bd37e4b38
--- /dev/null
+++ b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/web-components.html
@@ -0,0 +1,22 @@
+
+ Back
+
+
+Question 3 of 9
+
+
+
+
+
+
+
+
+
+ Save and continue
+
+
+
diff --git a/docs/src/content/examples/show-a-user-progress-when-the-time-is-unknown/angular.html b/docs/src/content/examples/show-a-user-progress-when-the-time-is-unknown/angular.html
new file mode 100644
index 0000000000..c32f2a73a7
--- /dev/null
+++ b/docs/src/content/examples/show-a-user-progress-when-the-time-is-unknown/angular.html
@@ -0,0 +1,5 @@
+
+
+
+ Search case history
+
diff --git a/docs/src/content/examples/show-a-user-progress-when-the-time-is-unknown/angular.ts b/docs/src/content/examples/show-a-user-progress-when-the-time-is-unknown/angular.ts
new file mode 100644
index 0000000000..a2406b6f28
--- /dev/null
+++ b/docs/src/content/examples/show-a-user-progress-when-the-time-is-unknown/angular.ts
@@ -0,0 +1,43 @@
+import { Component } from "@angular/core";
+import { TemporaryNotification } from "@abgov/ui-components-common";
+
+@Component({
+ selector: "app-show-a-user-progress-when-time-unknown",
+ templateUrl: "./angular.html",
+})
+export class ShowAUserProgressWhenTimeUnknownComponent {
+ async searchCMS(): Promise {
+ // Perform your API call here
+ await new Promise((resolve) => setTimeout(resolve, 3000));
+ return undefined;
+ }
+
+ async search(): Promise {
+ const uuid = TemporaryNotification.show("Searching case management system...", {
+ type: "indeterminate",
+ actionText: "Cancel",
+ action: () => {
+ TemporaryNotification.dismiss(uuid);
+ },
+ });
+
+ const err = await this.searchCMS();
+ if (err) {
+ TemporaryNotification.show("Could not connect to case history", {
+ type: "failure",
+ duration: "medium",
+ cancelUUID: uuid,
+ });
+ } else {
+ TemporaryNotification.show("Search complete - 47 records found", {
+ type: "success",
+ duration: "medium",
+ actionText: "View",
+ action: () => {
+ console.log("View search results clicked!");
+ },
+ cancelUUID: uuid,
+ });
+ }
+ }
+}
diff --git a/docs/src/content/examples/show-a-user-progress-when-the-time-is-unknown/index.mdx b/docs/src/content/examples/show-a-user-progress-when-the-time-is-unknown/index.mdx
new file mode 100644
index 0000000000..f55408e966
--- /dev/null
+++ b/docs/src/content/examples/show-a-user-progress-when-the-time-is-unknown/index.mdx
@@ -0,0 +1,35 @@
+---
+id: show-a-user-progress-when-the-time-is-unknown
+title: Show a user progress when the time is unknown
+categories:
+ - feedback-and-alerts
+scale: task
+userType: both
+tags:
+ - progress
+ - notification
+ - indeterminate
+ - search
+ - feedback
+components:
+ - temporary-notification
+ - button
+status: published
+---
+
+Display indeterminate progress for operations where completion time cannot be estimated, such as complex searches or external system queries.
+
+## When to use
+
+Use this pattern when:
+- The operation duration cannot be predicted
+- You're querying external systems with variable response times
+- Searching across multiple data sources
+- Users need to know something is happening but not a specific percentage
+
+## Considerations
+
+- Use `type="indeterminate"` for unknown duration operations
+- Always provide a cancel option
+- Show success or failure notification when complete
+- Include meaningful context in the notification message
diff --git a/docs/src/content/examples/show-a-user-progress-when-the-time-is-unknown/react.tsx b/docs/src/content/examples/show-a-user-progress-when-the-time-is-unknown/react.tsx
new file mode 100644
index 0000000000..b3a7e478dd
--- /dev/null
+++ b/docs/src/content/examples/show-a-user-progress-when-the-time-is-unknown/react.tsx
@@ -0,0 +1,48 @@
+import { GoabButton, GoabTemporaryNotificationCtrl } from "@abgov/react-components";
+import { TemporaryNotification } from "@abgov/ui-components-common";
+
+export function ShowAUserProgressWhenTheTimeIsUnknown() {
+ const searchCMS = async (): Promise => {
+ // Perform your API call here
+ await new Promise((resolve) => setTimeout(resolve, 3000));
+ return undefined;
+ };
+
+ const search = async () => {
+ const uuid = TemporaryNotification.show("Searching case management system...", {
+ type: "indeterminate",
+ actionText: "Cancel",
+ action: () => {
+ TemporaryNotification.dismiss(uuid);
+ },
+ });
+
+ const err = await searchCMS();
+ if (err) {
+ TemporaryNotification.show("Could not connect to case history", {
+ type: "failure",
+ duration: "medium",
+ cancelUUID: uuid,
+ });
+ } else {
+ TemporaryNotification.show("Search complete - 47 records found", {
+ type: "success",
+ duration: "medium",
+ actionText: "View",
+ action: () => {
+ console.log("View search results clicked!");
+ },
+ cancelUUID: uuid,
+ });
+ }
+ };
+
+ return (
+ <>
+
+
+ Search case history
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/show-a-user-progress-when-the-time-is-unknown/web-components.html b/docs/src/content/examples/show-a-user-progress-when-the-time-is-unknown/web-components.html
new file mode 100644
index 0000000000..115acfa575
--- /dev/null
+++ b/docs/src/content/examples/show-a-user-progress-when-the-time-is-unknown/web-components.html
@@ -0,0 +1,69 @@
+
+
+
+ Search case history
+
+
+
diff --git a/docs/src/content/examples/show-a-user-progress/angular.html b/docs/src/content/examples/show-a-user-progress/angular.html
new file mode 100644
index 0000000000..360f5aa206
--- /dev/null
+++ b/docs/src/content/examples/show-a-user-progress/angular.html
@@ -0,0 +1,5 @@
+
+
+
+ Download report
+
diff --git a/docs/src/content/examples/show-a-user-progress/angular.ts b/docs/src/content/examples/show-a-user-progress/angular.ts
new file mode 100644
index 0000000000..2cec465c74
--- /dev/null
+++ b/docs/src/content/examples/show-a-user-progress/angular.ts
@@ -0,0 +1,51 @@
+import { Component } from "@angular/core";
+import { TemporaryNotification } from "@abgov/ui-components-common";
+
+@Component({
+ selector: "app-show-a-user-progress",
+ templateUrl: "./angular.html",
+})
+export class ShowAUserProgressComponent {
+ async downloadReportAPI(notificationUuid: string): Promise {
+ // Perform your API call here with progress tracking
+ // Update progress as download progresses (0-100)
+ TemporaryNotification.setProgress(notificationUuid, 25);
+ // ... continue API work ...
+ TemporaryNotification.setProgress(notificationUuid, 50);
+ // ... continue API work ...
+ TemporaryNotification.setProgress(notificationUuid, 75);
+ // ... complete API work ...
+ TemporaryNotification.setProgress(notificationUuid, 100);
+ return undefined;
+ }
+
+ async downloadReport(): Promise {
+ const uuid = TemporaryNotification.show("Downloading report D-23459", {
+ type: "progress",
+ actionText: "Cancel",
+ action: () => {
+ TemporaryNotification.dismiss(uuid);
+ },
+ });
+
+ const err = await this.downloadReportAPI(uuid);
+
+ if (err) {
+ TemporaryNotification.show("Download failed", {
+ type: "error",
+ duration: "medium",
+ cancelUUID: uuid,
+ });
+ } else {
+ TemporaryNotification.show("Report downloaded", {
+ type: "success",
+ duration: "medium",
+ actionText: "View",
+ action: () => {
+ console.log("View report clicked!");
+ },
+ cancelUUID: uuid,
+ });
+ }
+ }
+}
diff --git a/docs/src/content/examples/show-a-user-progress/index.mdx b/docs/src/content/examples/show-a-user-progress/index.mdx
new file mode 100644
index 0000000000..7925fa564b
--- /dev/null
+++ b/docs/src/content/examples/show-a-user-progress/index.mdx
@@ -0,0 +1,34 @@
+---
+id: show-a-user-progress
+title: Show a user progress
+categories:
+ - feedback-and-alerts
+scale: task
+userType: both
+tags:
+ - progress
+ - notification
+ - download
+ - feedback
+components:
+ - temporary-notification
+ - button
+status: published
+---
+
+Display progress feedback during long-running operations like downloads, showing percentage completion with the ability to cancel and receive success confirmation.
+
+## When to use
+
+Use this pattern when:
+- An operation takes more than a few seconds
+- Progress can be measured as a percentage (0-100%)
+- Users need the ability to cancel the operation
+- Success or failure confirmation is needed
+
+## Considerations
+
+- Always provide a cancel option for long operations
+- Show a success notification when complete
+- Use `type="progress"` for operations with known duration
+- Handle errors gracefully with failure notifications
diff --git a/docs/src/content/examples/show-a-user-progress/react.tsx b/docs/src/content/examples/show-a-user-progress/react.tsx
new file mode 100644
index 0000000000..600b4205d4
--- /dev/null
+++ b/docs/src/content/examples/show-a-user-progress/react.tsx
@@ -0,0 +1,77 @@
+import { GoabButton, GoabTemporaryNotificationCtrl } from "@abgov/react-components";
+import { TemporaryNotification } from "@abgov/ui-components-common";
+
+export function ShowAUserProgress() {
+ const sendApi = (
+ progressCallback: (progress: number) => void,
+ isCancelledRef: { current: boolean }
+ ) => {
+ return new Promise((resolve, reject) => {
+ let progress = 0;
+ const interval = setInterval(() => {
+ if (isCancelledRef.current) {
+ clearInterval(interval);
+ reject("cancelled");
+ return;
+ }
+
+ progress += 5;
+ progressCallback(progress);
+
+ if (progress >= 100) {
+ clearInterval(interval);
+ resolve("success");
+ }
+ }, 200);
+ });
+ };
+
+ const downloadReport = () => {
+ const isCancelledRef = { current: false };
+
+ const uuid = TemporaryNotification.show("Downloading report D-23459", {
+ type: "progress",
+ actionText: "Cancel",
+ action: () => {
+ isCancelledRef.current = true;
+ TemporaryNotification.dismiss(uuid);
+ console.log("Download cancelled");
+ },
+ });
+
+ TemporaryNotification.setProgress(uuid, 0);
+
+ const updateProgress = (progress: number) => {
+ TemporaryNotification.setProgress(uuid, progress);
+
+ if (progress >= 100) {
+ setTimeout(() => {
+ TemporaryNotification.show("Report downloaded", {
+ type: "success",
+ duration: "medium",
+ actionText: "View",
+ action: () => {
+ console.log("View report clicked!");
+ },
+ cancelUUID: uuid,
+ });
+ }, 300);
+ }
+ };
+
+ sendApi(updateProgress, isCancelledRef).catch((error) => {
+ if (error !== "cancelled") {
+ TemporaryNotification.dismiss(uuid);
+ }
+ });
+ };
+
+ return (
+ <>
+
+
+ Download report
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/show-a-user-progress/web-components.html b/docs/src/content/examples/show-a-user-progress/web-components.html
new file mode 100644
index 0000000000..391345d75b
--- /dev/null
+++ b/docs/src/content/examples/show-a-user-progress/web-components.html
@@ -0,0 +1,86 @@
+
+
+
+ Download report
+
+
+
diff --git a/docs/src/content/examples/show-different-views-of-data-in-a-table/angular.html b/docs/src/content/examples/show-different-views-of-data-in-a-table/angular.html
new file mode 100644
index 0000000000..a10760fbc0
--- /dev/null
+++ b/docs/src/content/examples/show-different-views-of-data-in-a-table/angular.html
@@ -0,0 +1,70 @@
+
+
+
+
+
+
Status
+
Text
+
Number
+
Action
+
+
+
+
+
+
Lorem ipsum
+
1234567890
+
Action
+
+
+
+
Lorem Ipsum
+
1234567890
+
Action
+
+
+
+
+
+ Review pending
+
+
+
+
Status
+
Text
+
Number
+
Action
+
+
+
+
+
+
Lorem ipsum
+
1234567890
+
Action
+
+
+
+
+
+ Complete
+
+
+
+
Status
+
Text
+
Number
+
Action
+
+
+
+
+
+
Lorem Ipsum
+
1234567890
+
Action
+
+
+
+
+
diff --git a/docs/src/content/examples/show-different-views-of-data-in-a-table/angular.ts b/docs/src/content/examples/show-different-views-of-data-in-a-table/angular.ts
new file mode 100644
index 0000000000..bb03ddfab4
--- /dev/null
+++ b/docs/src/content/examples/show-different-views-of-data-in-a-table/angular.ts
@@ -0,0 +1,10 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-show-different-views-of-data-in-table",
+ templateUrl: "./angular.html",
+})
+export class ShowDifferentViewsOfDataInTableComponent {
+ reviewItems = [0, 1, 2, 3];
+ completeItems = [0, 1];
+}
diff --git a/docs/src/content/examples/show-different-views-of-data-in-a-table/index.mdx b/docs/src/content/examples/show-different-views-of-data-in-a-table/index.mdx
new file mode 100644
index 0000000000..42d1d0ac5a
--- /dev/null
+++ b/docs/src/content/examples/show-different-views-of-data-in-a-table/index.mdx
@@ -0,0 +1,38 @@
+---
+id: show-different-views-of-data-in-a-table
+title: Show different views of data in a table
+categories:
+ - content-layout
+scale: task
+userType: worker
+tags:
+ - table
+ - tabs
+ - filtering
+ - status
+ - data-views
+components:
+ - tabs
+ - tab
+ - table
+ - badge
+ - button
+status: published
+---
+
+Use tabs to organize table data into different views based on status or category, showing counts in each tab to help workers quickly navigate to relevant items.
+
+## When to use
+
+Use this pattern when:
+- Workers need to view data filtered by status
+- Different subsets of data require focused attention
+- Quick access to counts of items in each category is helpful
+- Switching between views should preserve context
+
+## Considerations
+
+- Show counts in tab headers using badges
+- Maintain consistent table structure across tabs
+- Default to the most commonly used view
+- Consider which statuses need prominent display
diff --git a/docs/src/content/examples/show-different-views-of-data-in-a-table/react.tsx b/docs/src/content/examples/show-different-views-of-data-in-a-table/react.tsx
new file mode 100644
index 0000000000..a7c5013fb8
--- /dev/null
+++ b/docs/src/content/examples/show-different-views-of-data-in-a-table/react.tsx
@@ -0,0 +1,121 @@
+import {
+ GoabBadge,
+ GoabButton,
+ GoabTab,
+ GoabTable,
+ GoabTabs,
+} from "@abgov/react-components";
+
+export function ShowDifferentViewsOfDataInATable() {
+ const review = [0, 1, 2, 3];
+ const complete = [0, 1];
+
+ return (
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/examples/show-full-date-in-a-tooltip/angular.html b/docs/src/content/examples/show-full-date-in-a-tooltip/angular.html
new file mode 100644
index 0000000000..0cf5b13d5e
--- /dev/null
+++ b/docs/src/content/examples/show-full-date-in-a-tooltip/angular.html
@@ -0,0 +1,11 @@
+
+
+ Joan Smith
+
+
+ 4 hours ago
+
+
+
+ Hover on the time it was added to see the full date and time.
+
diff --git a/docs/src/content/examples/show-full-date-in-a-tooltip/angular.ts b/docs/src/content/examples/show-full-date-in-a-tooltip/angular.ts
new file mode 100644
index 0000000000..20d638940d
--- /dev/null
+++ b/docs/src/content/examples/show-full-date-in-a-tooltip/angular.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-show-full-date-in-tooltip",
+ templateUrl: "./angular.html",
+})
+export class ShowFullDateInTooltipComponent {}
diff --git a/docs/src/content/examples/show-full-date-in-a-tooltip/index.mdx b/docs/src/content/examples/show-full-date-in-a-tooltip/index.mdx
new file mode 100644
index 0000000000..9f26836371
--- /dev/null
+++ b/docs/src/content/examples/show-full-date-in-a-tooltip/index.mdx
@@ -0,0 +1,34 @@
+---
+id: show-full-date-in-a-tooltip
+title: Show full date in a tooltip
+categories:
+ - inputs-and-actions
+scale: interaction
+userType: both
+tags:
+ - tooltip
+ - date
+ - relative-time
+ - hover
+components:
+ - tooltip
+ - container
+status: published
+---
+
+Display relative time (like "4 hours ago") while providing the full date and time on hover via tooltip for users who need exact timestamps.
+
+## When to use
+
+Use this pattern when:
+- Displaying relative time like "4 hours ago" or "2 days ago"
+- Users may need access to the exact date and time
+- Space is limited for full date display
+- Context cards or comments show timestamps
+
+## Considerations
+
+- Keep the relative time format consistent
+- Include both date and time in the tooltip
+- Style the hoverable text subtly (secondary color, smaller font)
+- Ensure tooltip is keyboard accessible
diff --git a/docs/src/content/examples/show-full-date-in-a-tooltip/react.tsx b/docs/src/content/examples/show-full-date-in-a-tooltip/react.tsx
new file mode 100644
index 0000000000..661f2f4ce7
--- /dev/null
+++ b/docs/src/content/examples/show-full-date-in-a-tooltip/react.tsx
@@ -0,0 +1,27 @@
+import { GoabContainer, GoabText, GoabTooltip } from "@abgov/react-components";
+
+export function ShowFullDateInATooltip() {
+ return (
+
+ Joan Smith
+
+
+ 4 hours ago
+
+
+
+ }
+ >
+ Hover on the time it was added to see the full date and time.
+
+ );
+}
diff --git a/docs/src/content/examples/show-full-date-in-a-tooltip/web-components.html b/docs/src/content/examples/show-full-date-in-a-tooltip/web-components.html
new file mode 100644
index 0000000000..ae2dfd247a
--- /dev/null
+++ b/docs/src/content/examples/show-full-date-in-a-tooltip/web-components.html
@@ -0,0 +1,11 @@
+
+
+ Joan Smith
+
+
+ 4 hours ago
+
+
+
+ Hover on the time it was added to see the full date and time.
+
diff --git a/docs/src/content/examples/show-links-to-navigation-items/angular.html b/docs/src/content/examples/show-links-to-navigation-items/angular.html
new file mode 100644
index 0000000000..7162209b3f
--- /dev/null
+++ b/docs/src/content/examples/show-links-to-navigation-items/angular.html
@@ -0,0 +1,20 @@
+
+
+ Arts and culture
+ Education and training
+ Family and social supports
+ Housing and community
+ Life events
+ Business and economy
+ Emergencies and public safety
+ Government
+ Jobs and employment
+ Moving to Alberta
+
+
+ Privacy
+ Disclaimer
+ Accessibility
+ Using Alberta.ca
+
+
diff --git a/docs/src/content/examples/show-links-to-navigation-items/angular.ts b/docs/src/content/examples/show-links-to-navigation-items/angular.ts
new file mode 100644
index 0000000000..1d58db8cf3
--- /dev/null
+++ b/docs/src/content/examples/show-links-to-navigation-items/angular.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-show-links-to-navigation-items",
+ templateUrl: "./angular.html",
+})
+export class ShowLinksToNavigationItemsComponent {}
diff --git a/docs/src/content/examples/show-links-to-navigation-items/index.mdx b/docs/src/content/examples/show-links-to-navigation-items/index.mdx
new file mode 100644
index 0000000000..ddfe62a417
--- /dev/null
+++ b/docs/src/content/examples/show-links-to-navigation-items/index.mdx
@@ -0,0 +1,35 @@
+---
+id: show-links-to-navigation-items
+title: Show links to navigation items
+categories:
+ - structure-and-navigation
+scale: task
+userType: both
+tags:
+ - footer
+ - navigation
+ - links
+ - sitemap
+components:
+ - footer
+ - footer-nav-section
+ - footer-meta-section
+status: published
+---
+
+Use the app footer to display comprehensive navigation links organized into sections, along with meta links for common utilities like privacy and accessibility.
+
+## When to use
+
+Use this pattern when:
+- Building a full-featured government service
+- Users need access to site-wide navigation in the footer
+- Meta links (privacy, accessibility, etc.) are required
+- Organizing footer links into logical categories helps navigation
+
+## Considerations
+
+- Group related links in the nav section
+- Keep meta section for utility links (privacy, accessibility, contact)
+- Control column layout with maxColumnCount prop
+- Ensure all links are properly labeled and functional
diff --git a/docs/src/content/examples/show-links-to-navigation-items/react.tsx b/docs/src/content/examples/show-links-to-navigation-items/react.tsx
new file mode 100644
index 0000000000..1f83491d55
--- /dev/null
+++ b/docs/src/content/examples/show-links-to-navigation-items/react.tsx
@@ -0,0 +1,30 @@
+import {
+ GoabAppFooter,
+ GoabAppFooterMetaSection,
+ GoabAppFooterNavSection,
+} from "@abgov/react-components";
+
+export function ShowLinksToNavigationItems() {
+ return (
+
+
+ Arts and culture
+ Education and training
+ Family and social supports
+ Housing and community
+ Life events
+ Business and economy
+ Emergencies and public safety
+ Government
+ Jobs and employment
+ Moving to Alberta
+
+
+ Privacy
+ Disclaimer
+ Accessibility
+ Using Alberta.ca
+
+
+ );
+}
diff --git a/docs/src/content/examples/show-links-to-navigation-items/web-components.html b/docs/src/content/examples/show-links-to-navigation-items/web-components.html
new file mode 100644
index 0000000000..209d41a1d5
--- /dev/null
+++ b/docs/src/content/examples/show-links-to-navigation-items/web-components.html
@@ -0,0 +1,20 @@
+
+
+ Arts and culture
+ Education and training
+ Family and social supports
+ Housing and community
+ Life events
+ Business and economy
+ Emergencies and public safety
+ Government
+ Jobs and employment
+ Moving to Alberta
+
+
+ Privacy
+ Disclaimer
+ Accessibility
+ Using Alberta.ca
+
+
diff --git a/docs/src/content/examples/show-more-information-to-help-answer-a-question/angular.html b/docs/src/content/examples/show-more-information-to-help-answer-a-question/angular.html
new file mode 100644
index 0000000000..208a48ead9
--- /dev/null
+++ b/docs/src/content/examples/show-more-information-to-help-answer-a-question/angular.html
@@ -0,0 +1,23 @@
+
+ Back
+
+
+
+
+
+
+
+
+
+
+
We ask this question to determine if you are eligible for child care benefits.
+
+
+Save and continue
diff --git a/docs/src/content/examples/show-more-information-to-help-answer-a-question/angular.ts b/docs/src/content/examples/show-more-information-to-help-answer-a-question/angular.ts
new file mode 100644
index 0000000000..2fdc5180c3
--- /dev/null
+++ b/docs/src/content/examples/show-more-information-to-help-answer-a-question/angular.ts
@@ -0,0 +1,32 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-show-more-info-to-help-answer-question",
+ templateUrl: "./angular.html",
+ styles: [
+ `
+ .back-link::before {
+ content: "";
+ display: inline-block;
+ width: 42px;
+ height: 24px;
+ vertical-align: middle;
+ background: url('data:image/svg+xml,')
+ center center no-repeat;
+ }
+ .back-link:visited::before,
+ .back-link:hover::before {
+ background: url('data:image/svg+xml,')
+ center center no-repeat;
+ }
+ .back-link {
+ margin-top: var(--goa-space-m);
+ }
+ `,
+ ],
+})
+export class ShowMoreInfoToHelpAnswerQuestionComponent {
+ onRadioChange(event: Event): void {
+ console.log("Radio changed:", event);
+ }
+}
diff --git a/docs/src/content/examples/show-more-information-to-help-answer-a-question/index.mdx b/docs/src/content/examples/show-more-information-to-help-answer-a-question/index.mdx
new file mode 100644
index 0000000000..0ea537d3b1
--- /dev/null
+++ b/docs/src/content/examples/show-more-information-to-help-answer-a-question/index.mdx
@@ -0,0 +1,38 @@
+---
+id: show-more-information-to-help-answer-a-question
+title: Show more information to help answer a question
+categories:
+ - forms
+scale: task
+userType: citizen
+tags:
+ - form
+ - details
+ - help
+ - question-page
+ - expandable
+components:
+ - details
+ - form-item
+ - radio-group
+ - radio-item
+ - button
+status: published
+---
+
+Use the Details component to provide optional contextual help that explains why a question is being asked, helping users understand the purpose without cluttering the main form.
+
+## When to use
+
+Use this pattern when:
+- Users may wonder why a question is being asked
+- Additional context helps users answer correctly
+- The information is optional and shouldn't distract
+- Following question page patterns for citizen services
+
+## Considerations
+
+- Place the details component after the question input
+- Use a clear heading like "Why are we asking this question?"
+- Keep the expanded content concise and helpful
+- Include helper text for the main question when appropriate
diff --git a/docs/src/content/examples/show-more-information-to-help-answer-a-question/react.tsx b/docs/src/content/examples/show-more-information-to-help-answer-a-question/react.tsx
new file mode 100644
index 0000000000..a6ff328b49
--- /dev/null
+++ b/docs/src/content/examples/show-more-information-to-help-answer-a-question/react.tsx
@@ -0,0 +1,42 @@
+import {
+ GoabButton,
+ GoabDetails,
+ GoabFormItem,
+ GoabLink,
+ GoabRadioGroup,
+ GoabRadioItem,
+} from "@abgov/react-components";
+
+export function ShowMoreInformationToHelpAnswerAQuestion() {
+ return (
+ <>
+
+ Back
+
+
+
+ {}}
+ >
+
+
+
+
+
+
+
We ask this question to determine if you are eligible for child care benefits.
+
+
+
+ Save and continue
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/show-more-information-to-help-answer-a-question/web-components.html b/docs/src/content/examples/show-more-information-to-help-answer-a-question/web-components.html
new file mode 100644
index 0000000000..c0eeae0297
--- /dev/null
+++ b/docs/src/content/examples/show-more-information-to-help-answer-a-question/web-components.html
@@ -0,0 +1,22 @@
+
+ Back
+
+
+
+
+
+
+
+
+
+
+
We ask this question to determine if you are eligible for child care benefits.
+
+
+Save and continue
diff --git a/docs/src/content/examples/show-multiple-actions-in-a-compact-table/angular.html b/docs/src/content/examples/show-multiple-actions-in-a-compact-table/angular.html
new file mode 100644
index 0000000000..e5870ba3c9
--- /dev/null
+++ b/docs/src/content/examples/show-multiple-actions-in-a-compact-table/angular.html
@@ -0,0 +1,26 @@
+
+
+
+
Status
+
Name
+
Id Number
+
Edit | Flag | Send
+
+
+
+
+
+
+
+
{{ row.name }}
+
{{ row.id }}
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/examples/show-multiple-actions-in-a-compact-table/angular.ts b/docs/src/content/examples/show-multiple-actions-in-a-compact-table/angular.ts
new file mode 100644
index 0000000000..7441e24480
--- /dev/null
+++ b/docs/src/content/examples/show-multiple-actions-in-a-compact-table/angular.ts
@@ -0,0 +1,23 @@
+import { Component } from "@angular/core";
+
+interface TableRow {
+ status: string;
+ statusText: string;
+ name: string;
+ id: number;
+}
+
+@Component({
+ selector: "app-show-multiple-actions-compact-table",
+ templateUrl: "./angular.html",
+})
+export class ShowMultipleActionsCompactTableComponent {
+ rows: TableRow[] = [
+ { status: "information", statusText: "In progress", name: "Darlene Robertson", id: 45904 },
+ { status: "dark", statusText: "Inactive", name: "Floyd Miles", id: 47838 },
+ { status: "success", statusText: "Active", name: "Kathryn Murphy", id: 34343 },
+ { status: "important", statusText: "Recent", name: "Annette Black", id: 89897 },
+ { status: "success", statusText: "Active", name: "Esther Howard", id: 12323 },
+ { status: "success", statusText: "Active", name: "Jane Cooper", id: 56565 },
+ ];
+}
diff --git a/docs/src/content/examples/show-multiple-actions-in-a-compact-table/index.mdx b/docs/src/content/examples/show-multiple-actions-in-a-compact-table/index.mdx
new file mode 100644
index 0000000000..6b0c1ebc92
--- /dev/null
+++ b/docs/src/content/examples/show-multiple-actions-in-a-compact-table/index.mdx
@@ -0,0 +1,37 @@
+---
+id: show-multiple-actions-in-a-compact-table
+title: Show multiple actions in a compact table
+categories:
+ - content-layout
+scale: task
+userType: worker
+tags:
+ - table
+ - icon-button
+ - actions
+ - compact
+ - worker-ui
+components:
+ - table
+ - icon-button
+ - badge
+ - block
+status: published
+---
+
+Use icon buttons to provide multiple row actions in tables where space is limited, keeping the interface compact while maintaining accessibility through aria labels.
+
+## When to use
+
+Use this pattern when:
+- Tables need multiple actions per row
+- Horizontal space is limited
+- Workers are familiar with icon meanings
+- Actions are common (edit, flag, send, etc.)
+
+## Considerations
+
+- Always include aria-label for accessibility
+- Use small size icon buttons for compact tables
+- Group related actions with GoabBlock
+- Ensure icons are universally understood
diff --git a/docs/src/content/examples/show-multiple-actions-in-a-compact-table/react.tsx b/docs/src/content/examples/show-multiple-actions-in-a-compact-table/react.tsx
new file mode 100644
index 0000000000..44e0970a55
--- /dev/null
+++ b/docs/src/content/examples/show-multiple-actions-in-a-compact-table/react.tsx
@@ -0,0 +1,52 @@
+import {
+ GoabBadge,
+ GoabBlock,
+ GoabIconButton,
+ GoabTable,
+} from "@abgov/react-components";
+
+export function ShowMultipleActionsInACompactTable() {
+ const rows = [
+ { status: "information", statusText: "In progress", name: "Darlene Robertson", id: 45904 },
+ { status: "dark", statusText: "Inactive", name: "Floyd Miles", id: 47838 },
+ { status: "success", statusText: "Active", name: "Kathryn Murphy", id: 34343 },
+ { status: "important", statusText: "Recent", name: "Annette Black", id: 89897 },
+ { status: "success", statusText: "Active", name: "Esther Howard", id: 12323 },
+ { status: "success", statusText: "Active", name: "Jane Cooper", id: 56565 },
+ ];
+
+ return (
+
+
+
+
+
+
+
+ Show
+
+
+
+
+
+ per page
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/examples/show-quick-links/angular.html b/docs/src/content/examples/show-quick-links/angular.html
new file mode 100644
index 0000000000..126a2b73bf
--- /dev/null
+++ b/docs/src/content/examples/show-quick-links/angular.html
@@ -0,0 +1,8 @@
+
+
+ Give feedback
+ Accessibility
+ Privacy
+ Contact us
+
+
diff --git a/docs/src/content/examples/show-quick-links/angular.ts b/docs/src/content/examples/show-quick-links/angular.ts
new file mode 100644
index 0000000000..4ba32c2555
--- /dev/null
+++ b/docs/src/content/examples/show-quick-links/angular.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-show-quick-links",
+ templateUrl: "./angular.html",
+})
+export class ShowQuickLinksComponent {}
diff --git a/docs/src/content/examples/show-quick-links/index.mdx b/docs/src/content/examples/show-quick-links/index.mdx
new file mode 100644
index 0000000000..c7569f386d
--- /dev/null
+++ b/docs/src/content/examples/show-quick-links/index.mdx
@@ -0,0 +1,34 @@
+---
+id: show-quick-links
+title: Show quick links
+categories:
+ - structure-and-navigation
+scale: task
+userType: both
+tags:
+ - footer
+ - navigation
+ - meta-links
+ - quick-access
+components:
+ - footer
+ - footer-meta-section
+status: published
+---
+
+Use the app footer meta section to display essential quick links like feedback, accessibility, privacy, and contact information without the full navigation structure.
+
+## When to use
+
+Use this pattern when:
+- Building a simpler service that doesn't need full navigation
+- Essential utility links are required in the footer
+- The service needs quick access to feedback/contact
+- Full footer navigation would be excessive
+
+## Considerations
+
+- Keep the meta section links focused and essential
+- Include accessibility and privacy links as required
+- Order links by importance or frequency of use
+- Use consistent link text across government services
diff --git a/docs/src/content/examples/show-quick-links/react.tsx b/docs/src/content/examples/show-quick-links/react.tsx
new file mode 100644
index 0000000000..4ab1be0cc2
--- /dev/null
+++ b/docs/src/content/examples/show-quick-links/react.tsx
@@ -0,0 +1,14 @@
+import { GoabAppFooter, GoabAppFooterMetaSection } from "@abgov/react-components";
+
+export function ShowQuickLinks() {
+ return (
+
+
+ Give feedback
+ Accessibility
+ Privacy
+ Contact us
+
+
+ );
+}
diff --git a/docs/src/content/examples/show-quick-links/web-components.html b/docs/src/content/examples/show-quick-links/web-components.html
new file mode 100644
index 0000000000..ac65f03bc0
--- /dev/null
+++ b/docs/src/content/examples/show-quick-links/web-components.html
@@ -0,0 +1,8 @@
+
+
+ Give feedback
+ Accessibility
+ Privacy
+ Contact us
+
+
diff --git a/docs/src/content/examples/show-status-in-a-table/angular.html b/docs/src/content/examples/show-status-in-a-table/angular.html
new file mode 100644
index 0000000000..d0b1cd40d6
--- /dev/null
+++ b/docs/src/content/examples/show-status-in-a-table/angular.html
@@ -0,0 +1,22 @@
+
+
+
+
Status
+
Name
+
File number
+
+
+
+
+
+
+
+
+
Lorem ipsum dolor sit amet consectetur.
+
1234567890
+
+ Assign
+
+
+
+
diff --git a/docs/src/content/examples/show-status-in-a-table/angular.ts b/docs/src/content/examples/show-status-in-a-table/angular.ts
new file mode 100644
index 0000000000..9d9c186a6e
--- /dev/null
+++ b/docs/src/content/examples/show-status-in-a-table/angular.ts
@@ -0,0 +1,26 @@
+import { Component } from "@angular/core";
+import type { GoabBadgeType } from "@abgov/ui-components-common";
+
+interface BadgeValue {
+ type: GoabBadgeType;
+ content: string;
+}
+
+@Component({
+ selector: "app-show-status-in-a-table",
+ templateUrl: "./angular.html",
+})
+export class ShowStatusInATableComponent {
+ badgeValues: BadgeValue[] = [
+ { type: "important", content: "Pending" },
+ { type: "emergency", content: "Failed" },
+ { type: "success", content: "Complete" },
+ { type: "information", content: "In progress" },
+ { type: "midtone", content: "Closed" },
+ { type: "success", content: "Complete" },
+ ];
+
+ onClick(): void {
+ console.log("clicked");
+ }
+}
diff --git a/docs/src/content/examples/show-status-in-a-table/index.mdx b/docs/src/content/examples/show-status-in-a-table/index.mdx
new file mode 100644
index 0000000000..a7297d4c17
--- /dev/null
+++ b/docs/src/content/examples/show-status-in-a-table/index.mdx
@@ -0,0 +1,33 @@
+---
+id: show-status-in-a-table
+title: Show status in a table
+categories:
+ - content-layout
+scale: task
+userType: worker
+tags:
+ - table
+ - badge
+ - status
+components:
+ - table
+ - badge
+ - button
+status: published
+---
+
+Display status information within table rows using badges to provide clear visual indicators of item states like pending, complete, failed, or in progress.
+
+## When to use
+
+Use this pattern when:
+- Displaying lists of items that have different status states
+- Workers need to quickly scan and identify items requiring action
+- Status needs to be immediately visible alongside other item data
+
+## Considerations
+
+- Use consistent badge types for similar statuses across your application
+- Choose badge colors that clearly differentiate between states (success, warning, error, info)
+- Include action buttons to allow workers to act on items directly from the table
+- Align status badges consistently within the column
diff --git a/docs/src/content/examples/show-status-in-a-table/react.tsx b/docs/src/content/examples/show-status-in-a-table/react.tsx
new file mode 100644
index 0000000000..a5abddc582
--- /dev/null
+++ b/docs/src/content/examples/show-status-in-a-table/react.tsx
@@ -0,0 +1,56 @@
+import {
+ GoabBadge,
+ GoabButton,
+ GoabTable,
+} from "@abgov/react-components";
+import type { GoabBadgeType } from "@abgov/ui-components-common";
+
+interface BadgeValue {
+ key: number;
+ type: GoabBadgeType;
+ content: string;
+}
+
+export function ShowStatusInATable() {
+ const badgeValues: BadgeValue[] = [
+ { key: 1, type: "important", content: "Pending" },
+ { key: 2, type: "emergency", content: "Failed" },
+ { key: 3, type: "success", content: "Complete" },
+ { key: 4, type: "information", content: "In progress" },
+ { key: 5, type: "midtone", content: "Closed" },
+ { key: 6, type: "success", content: "Complete" },
+ ];
+
+ const handleClick = () => {
+ console.log("clicked");
+ };
+
+ return (
+
+
+
+
+
+
diff --git a/docs/src/content/examples/show-status-on-a-card/angular.html b/docs/src/content/examples/show-status-on-a-card/angular.html
new file mode 100644
index 0000000000..31053be028
--- /dev/null
+++ b/docs/src/content/examples/show-status-on-a-card/angular.html
@@ -0,0 +1,7 @@
+
+ Heading
+
+
+
+ Content
+
diff --git a/docs/src/content/examples/show-status-on-a-card/angular.ts b/docs/src/content/examples/show-status-on-a-card/angular.ts
new file mode 100644
index 0000000000..a38a831d9e
--- /dev/null
+++ b/docs/src/content/examples/show-status-on-a-card/angular.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-show-status-on-a-card",
+ templateUrl: "./angular.html",
+})
+export class ShowStatusOnACardComponent {}
diff --git a/docs/src/content/examples/show-status-on-a-card/index.mdx b/docs/src/content/examples/show-status-on-a-card/index.mdx
new file mode 100644
index 0000000000..797a32d9fe
--- /dev/null
+++ b/docs/src/content/examples/show-status-on-a-card/index.mdx
@@ -0,0 +1,33 @@
+---
+id: show-status-on-a-card
+title: Show status on a card
+categories:
+ - content-layout
+scale: task
+userType: worker
+tags:
+ - card
+ - container
+ - badge
+ - status
+components:
+ - container
+ - badge
+status: published
+---
+
+Display status indicators on cards using badges in the actions slot, allowing workers to quickly see the priority or state of each item.
+
+## When to use
+
+Use this pattern when:
+- Displaying items in a card-based layout that have status or priority levels
+- Workers need to quickly identify high-priority or important items
+- Status should be prominently visible in the card header area
+
+## Considerations
+
+- Use the actions slot to position the badge in the card header
+- Choose badge types that clearly communicate priority or status
+- Keep badge content concise (one or two words)
+- Ensure the card heading and badge work well together visually
diff --git a/docs/src/content/examples/show-status-on-a-card/react.tsx b/docs/src/content/examples/show-status-on-a-card/react.tsx
new file mode 100644
index 0000000000..9c16f23258
--- /dev/null
+++ b/docs/src/content/examples/show-status-on-a-card/react.tsx
@@ -0,0 +1,14 @@
+import { GoabBadge, GoabContainer } from "@abgov/react-components";
+
+export function ShowStatusOnACard() {
+ return (
+ }
+ >
+ Content
+
+ );
+}
diff --git a/docs/src/content/examples/show-status-on-a-card/web-components.html b/docs/src/content/examples/show-status-on-a-card/web-components.html
new file mode 100644
index 0000000000..ba27a4d6ad
--- /dev/null
+++ b/docs/src/content/examples/show-status-on-a-card/web-components.html
@@ -0,0 +1,7 @@
+
+
Heading
+
+
+
+ Content
+
diff --git a/docs/src/content/examples/show-version-number/angular.html b/docs/src/content/examples/show-version-number/angular.html
new file mode 100644
index 0000000000..de826db41a
--- /dev/null
+++ b/docs/src/content/examples/show-version-number/angular.html
@@ -0,0 +1,6 @@
+
+
+ Slotted version text.
+ v1.23
+
+
diff --git a/docs/src/content/examples/show-version-number/angular.ts b/docs/src/content/examples/show-version-number/angular.ts
new file mode 100644
index 0000000000..3373675850
--- /dev/null
+++ b/docs/src/content/examples/show-version-number/angular.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-show-version-number",
+ templateUrl: "./angular.html",
+})
+export class ShowVersionNumberComponent {}
diff --git a/docs/src/content/examples/show-version-number/index.mdx b/docs/src/content/examples/show-version-number/index.mdx
new file mode 100644
index 0000000000..17b53482f7
--- /dev/null
+++ b/docs/src/content/examples/show-version-number/index.mdx
@@ -0,0 +1,32 @@
+---
+id: show-version-number
+title: Show version number
+categories:
+ - inputs-and-actions
+scale: interaction
+userType: both
+tags:
+ - microsite-header
+ - version
+ - alpha
+ - beta
+components:
+ - microsite-header
+status: published
+---
+
+Display version information in the microsite header using the version slot, allowing custom formatting and styling of version text.
+
+## When to use
+
+Use this pattern when:
+- You need to display a version number or status in the header
+- The service is in alpha or beta phase
+- You want to include formatted version information
+
+## Considerations
+
+- Use the version slot for custom version content with formatting
+- Keep version text concise and clear
+- Combine with header type (alpha, beta, live) to indicate service maturity
+- Version information should be easily scannable
diff --git a/docs/src/content/examples/show-version-number/react.tsx b/docs/src/content/examples/show-version-number/react.tsx
new file mode 100644
index 0000000000..48e3faec58
--- /dev/null
+++ b/docs/src/content/examples/show-version-number/react.tsx
@@ -0,0 +1,15 @@
+import { GoabMicrositeHeader } from "@abgov/react-components";
+
+export function ShowVersionNumber() {
+ return (
+
+ Slotted version text.
+ v1.23
+ >
+ }
+ />
+ );
+}
diff --git a/docs/src/content/examples/show-version-number/web-components.html b/docs/src/content/examples/show-version-number/web-components.html
new file mode 100644
index 0000000000..f27843b0de
--- /dev/null
+++ b/docs/src/content/examples/show-version-number/web-components.html
@@ -0,0 +1,6 @@
+
+
+ Slotted version text.
+ v1.23
+
+
diff --git a/docs/src/content/examples/slotted-error-text-in-a-form-item/angular.html b/docs/src/content/examples/slotted-error-text-in-a-form-item/angular.html
new file mode 100644
index 0000000000..684090522d
--- /dev/null
+++ b/docs/src/content/examples/slotted-error-text-in-a-form-item/angular.html
@@ -0,0 +1,8 @@
+
+
+
+ This is
+ slotted
+ error text.
+
+
diff --git a/docs/src/content/examples/slotted-error-text-in-a-form-item/angular.ts b/docs/src/content/examples/slotted-error-text-in-a-form-item/angular.ts
new file mode 100644
index 0000000000..d56ef873e1
--- /dev/null
+++ b/docs/src/content/examples/slotted-error-text-in-a-form-item/angular.ts
@@ -0,0 +1,16 @@
+import { Component } from "@angular/core";
+import { FormBuilder, FormGroup } from "@angular/forms";
+
+@Component({
+ selector: "app-slotted-error-text-in-a-form-item",
+ templateUrl: "./angular.html",
+})
+export class SlottedErrorTextInAFormItemComponent {
+ form: FormGroup;
+
+ constructor(private fb: FormBuilder) {
+ this.form = this.fb.group({
+ item: [""],
+ });
+ }
+}
diff --git a/docs/src/content/examples/slotted-error-text-in-a-form-item/index.mdx b/docs/src/content/examples/slotted-error-text-in-a-form-item/index.mdx
new file mode 100644
index 0000000000..ecd44849e2
--- /dev/null
+++ b/docs/src/content/examples/slotted-error-text-in-a-form-item/index.mdx
@@ -0,0 +1,34 @@
+---
+id: slotted-error-text-in-a-form-item
+title: Slotted error text in a form item
+categories:
+ - forms
+scale: interaction
+userType: both
+tags:
+ - form
+ - form-item
+ - error
+ - validation
+ - slot
+components:
+ - form-item
+ - input
+status: published
+---
+
+Use the error slot in a form item to display formatted error messages with custom styling like bold or italic text.
+
+## When to use
+
+Use this pattern when:
+- You need to display error messages with custom formatting
+- Error text requires links, bold, or other inline styling
+- Standard string-based error messages are insufficient
+
+## Considerations
+
+- Keep error messages clear and actionable
+- Use formatting sparingly to highlight key information
+- Ensure error text is accessible and readable by screen readers
+- The input component should also have its error prop set to true for proper styling
diff --git a/docs/src/content/examples/slotted-error-text-in-a-form-item/react.tsx b/docs/src/content/examples/slotted-error-text-in-a-form-item/react.tsx
new file mode 100644
index 0000000000..6da6c6c825
--- /dev/null
+++ b/docs/src/content/examples/slotted-error-text-in-a-form-item/react.tsx
@@ -0,0 +1,23 @@
+import { useState } from "react";
+import { GoabFormItem, GoabInput } from "@abgov/react-components";
+import type { GoabInputOnChangeDetail } from "@abgov/ui-components-common";
+
+export function SlottedErrorTextInAFormItem() {
+ const [value, setValue] = useState("");
+
+ const onChange = (detail: GoabInputOnChangeDetail) => {
+ setValue(detail.value);
+ };
+
+ const errorMessage = (
+ <>
+ This is slotted error text.
+ >
+ );
+
+ return (
+
+
+
+ );
+}
diff --git a/docs/src/content/examples/slotted-error-text-in-a-form-item/web-components.html b/docs/src/content/examples/slotted-error-text-in-a-form-item/web-components.html
new file mode 100644
index 0000000000..ed6988352a
--- /dev/null
+++ b/docs/src/content/examples/slotted-error-text-in-a-form-item/web-components.html
@@ -0,0 +1,15 @@
+
+
+
+ This is
+ slotted
+ error text.
+
+
+
+
diff --git a/docs/src/content/examples/slotted-helper-text-in-a-form-item/angular.html b/docs/src/content/examples/slotted-helper-text-in-a-form-item/angular.html
new file mode 100644
index 0000000000..010e8112fa
--- /dev/null
+++ b/docs/src/content/examples/slotted-helper-text-in-a-form-item/angular.html
@@ -0,0 +1,8 @@
+
+
+
+ This is
+ slotted
+ help text.
+
+
diff --git a/docs/src/content/examples/slotted-helper-text-in-a-form-item/angular.ts b/docs/src/content/examples/slotted-helper-text-in-a-form-item/angular.ts
new file mode 100644
index 0000000000..864372da1c
--- /dev/null
+++ b/docs/src/content/examples/slotted-helper-text-in-a-form-item/angular.ts
@@ -0,0 +1,16 @@
+import { Component } from "@angular/core";
+import { FormBuilder, FormGroup } from "@angular/forms";
+
+@Component({
+ selector: "app-slotted-helper-text-in-a-form-item",
+ templateUrl: "./angular.html",
+})
+export class SlottedHelperTextInAFormItemComponent {
+ form: FormGroup;
+
+ constructor(private fb: FormBuilder) {
+ this.form = this.fb.group({
+ item: [""],
+ });
+ }
+}
diff --git a/docs/src/content/examples/slotted-helper-text-in-a-form-item/index.mdx b/docs/src/content/examples/slotted-helper-text-in-a-form-item/index.mdx
new file mode 100644
index 0000000000..a9426f03f3
--- /dev/null
+++ b/docs/src/content/examples/slotted-helper-text-in-a-form-item/index.mdx
@@ -0,0 +1,33 @@
+---
+id: slotted-helper-text-in-a-form-item
+title: Slotted helper text in a form item
+categories:
+ - forms
+scale: interaction
+userType: both
+tags:
+ - form
+ - form-item
+ - helper-text
+ - slot
+components:
+ - form-item
+ - input
+status: published
+---
+
+Use the helpText slot in a form item to display formatted helper text with custom styling like bold, italic, or links.
+
+## When to use
+
+Use this pattern when:
+- You need to display helper text with custom formatting
+- Helper text requires links to additional resources
+- Standard string-based helper text is insufficient
+
+## Considerations
+
+- Keep helper text concise and relevant to the field
+- Use formatting to highlight important information
+- Ensure helper text is accessible to screen readers
+- Consider using links to provide additional guidance without cluttering the form
diff --git a/docs/src/content/examples/slotted-helper-text-in-a-form-item/react.tsx b/docs/src/content/examples/slotted-helper-text-in-a-form-item/react.tsx
new file mode 100644
index 0000000000..9f4304f479
--- /dev/null
+++ b/docs/src/content/examples/slotted-helper-text-in-a-form-item/react.tsx
@@ -0,0 +1,23 @@
+import { useState } from "react";
+import { GoabFormItem, GoabInput } from "@abgov/react-components";
+import type { GoabInputOnChangeDetail } from "@abgov/ui-components-common";
+
+export function SlottedHelperTextInAFormItem() {
+ const [value, setValue] = useState("");
+
+ const onChange = (detail: GoabInputOnChangeDetail) => {
+ setValue(detail.value);
+ };
+
+ const helpText = (
+ <>
+ This is slotted help text.
+ >
+ );
+
+ return (
+
+
+
+ );
+}
diff --git a/docs/src/content/examples/slotted-helper-text-in-a-form-item/web-components.html b/docs/src/content/examples/slotted-helper-text-in-a-form-item/web-components.html
new file mode 100644
index 0000000000..758be354ed
--- /dev/null
+++ b/docs/src/content/examples/slotted-helper-text-in-a-form-item/web-components.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
diff --git a/docs/src/content/examples/start-page/angular.html b/docs/src/content/examples/start-page/angular.html
new file mode 100644
index 0000000000..0101ce48dd
--- /dev/null
+++ b/docs/src/content/examples/start-page/angular.html
@@ -0,0 +1,32 @@
+Name of service
+
+ A short overview of the service. This is a couple sentences that helps the user understand what the service is.
+
+Use this service to apply for [service]. You can use this service to:
+
+
see if you or a family member is eligible for [service]
+
create and submit an application for [service]
+
continue an application for [service] that you already started
+
+
+Before you begin
+The application form should take about 20 minutes to complete.
+
+ In order to complete the application you will need:
+
+
+
government issued ID for the person applying
+
+
+ Get started
+
+
+Other information about the service
+
+ This section contains supplementary details about the service, including descriptions of less common scenarios, exceptions, and additional resources available. It provides context and additional insights that may be relevant to your specific circumstances or interests, helping you understand the full scope and utility of the service offered.
+
+
+Support
+
+ For assistance, email us at help@gov.ab.ca
+
diff --git a/docs/src/content/examples/start-page/angular.ts b/docs/src/content/examples/start-page/angular.ts
new file mode 100644
index 0000000000..e8b4f724e4
--- /dev/null
+++ b/docs/src/content/examples/start-page/angular.ts
@@ -0,0 +1,23 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-start-page",
+ templateUrl: "./angular.html",
+ styles: [`
+ .page-title {
+ margin-bottom: var(--goa-space-l);
+ }
+ h2 {
+ margin-top: var(--goa-space-xl);
+ margin-bottom: 0;
+ }
+ h2 + p {
+ margin-top: var(--goa-space-l);
+ }
+ `],
+})
+export class StartPageComponent {
+ onClick(): void {
+ console.log("Get started clicked");
+ }
+}
diff --git a/docs/src/content/examples/start-page/index.mdx b/docs/src/content/examples/start-page/index.mdx
new file mode 100644
index 0000000000..6e9db5d62e
--- /dev/null
+++ b/docs/src/content/examples/start-page/index.mdx
@@ -0,0 +1,33 @@
+---
+id: start-page
+title: Start page
+categories:
+ - forms
+scale: page
+userType: citizen
+tags:
+ - page
+ - service
+ - start
+ - citizen
+components:
+ - button
+status: published
+---
+
+A start page is the front door to a government service for citizens. It provides essential information about the service and a clear call to action to begin.
+
+## When to use
+
+Use this pattern when:
+- Creating the entry point for a citizen-facing government service
+- Citizens need to understand what the service does before starting
+- You need to communicate prerequisites, time estimates, or required documents
+
+## Considerations
+
+- Keep the overview concise and focused on what users can do
+- List what documents or information users will need
+- Include an estimated completion time
+- Use a prominent "Get started" or "Start now" button
+- Provide contact information and alternative ways to access the service below the main call to action
diff --git a/docs/src/content/examples/start-page/react.tsx b/docs/src/content/examples/start-page/react.tsx
new file mode 100644
index 0000000000..e0f84b71ed
--- /dev/null
+++ b/docs/src/content/examples/start-page/react.tsx
@@ -0,0 +1,48 @@
+import { GoabButton, GoabText } from "@abgov/react-components";
+
+export function StartPage() {
+ const handleClick = () => {
+ console.log("Get started clicked");
+ };
+
+ return (
+ <>
+ Name of service
+
+ A short overview of the service. This is a couple sentences that helps the user understand
+ what the service is.
+
+ Use this service to apply for [service]. You can use this service to:
+
+
see if you or a family member is eligible for [service]
+
create and submit an application for [service]
+
continue an application for [service] that you already started
+
+
+ Before you begin
+ The application form should take about 20 minutes to complete.
+
+ In order to complete the application you will need:
+
+
+
government issued ID for the person applying
+
+
+ Get started
+
+
+ Other information about the service
+
+ This section contains supplementary details about the service, including descriptions of
+ less common scenarios, exceptions, and additional resources available. It provides context
+ and additional insights that may be relevant to your specific circumstances or interests,
+ helping you understand the full scope and utility of the service offered.
+
+
+ Support
+
+ For assistance, email us at help@gov.ab.ca
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/start-page/web-components.html b/docs/src/content/examples/start-page/web-components.html
new file mode 100644
index 0000000000..c2eea9b917
--- /dev/null
+++ b/docs/src/content/examples/start-page/web-components.html
@@ -0,0 +1,36 @@
+Name of service
+
+ A short overview of the service. This is a couple sentences that helps the user understand what the service is.
+
+Use this service to apply for [service]. You can use this service to:
+
+
see if you or a family member is eligible for [service]
+
create and submit an application for [service]
+
continue an application for [service] that you already started
+
+
+Before you begin
+The application form should take about 20 minutes to complete.
+
+ In order to complete the application you will need:
+
+
+
government issued ID for the person applying
+
+Get started
+
+Other information about the service
+
+ This section contains supplementary details about the service, including descriptions of less common scenarios, exceptions, and additional resources available. It provides context and additional insights that may be relevant to your specific circumstances or interests, helping you understand the full scope and utility of the service offered.
+
+
+Support
+
+ For assistance, email us at help@gov.ab.ca
+
+
+
diff --git a/docs/src/content/examples/task-list-page/angular.html b/docs/src/content/examples/task-list-page/angular.html
new file mode 100644
index 0000000000..8d0cf5e078
--- /dev/null
+++ b/docs/src/content/examples/task-list-page/angular.html
@@ -0,0 +1,59 @@
+Apply for a service
+
+ You have completed 1 of 3 sections.
+
+
+1. Before you start
+
+
+
+
+
+
+3. Schedule service
+You need to complete the previous section before you can start this task.
+
+
+
+
Receive email confirmation
+
+
+
+
+
+
Pay service fee
+
+
+
+
+
+
diff --git a/docs/src/content/examples/task-list-page/angular.ts b/docs/src/content/examples/task-list-page/angular.ts
new file mode 100644
index 0000000000..d6e9ccc6c6
--- /dev/null
+++ b/docs/src/content/examples/task-list-page/angular.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-task-list-page",
+ templateUrl: "./angular.html",
+})
+export class TaskListPageComponent {}
diff --git a/docs/src/content/examples/task-list-page/index.mdx b/docs/src/content/examples/task-list-page/index.mdx
new file mode 100644
index 0000000000..de2e670764
--- /dev/null
+++ b/docs/src/content/examples/task-list-page/index.mdx
@@ -0,0 +1,36 @@
+---
+id: task-list-page
+title: Task list page
+categories:
+ - forms
+scale: page
+userType: both
+tags:
+ - page
+ - task-list
+ - progress
+ - form
+components:
+ - table
+ - badge
+ - callout
+status: published
+---
+
+A task list page provides a structure for multi-step services, showing users their progress through a series of tasks with clear status indicators.
+
+## When to use
+
+Use this pattern when:
+- A service has multiple distinct tasks or sections to complete
+- Users need to see their overall progress
+- Tasks can potentially be completed in different orders
+- Users may return to complete tasks over multiple sessions
+
+## Considerations
+
+- Group related actions into logical tasks
+- Show status badges for each task (Completed, In progress, Not started, Cannot start yet)
+- Include a summary callout showing how many sections are complete
+- Allow users to complete tasks in any order when possible
+- Clearly indicate when tasks have dependencies
diff --git a/docs/src/content/examples/task-list-page/react.tsx b/docs/src/content/examples/task-list-page/react.tsx
new file mode 100644
index 0000000000..98e1942c0d
--- /dev/null
+++ b/docs/src/content/examples/task-list-page/react.tsx
@@ -0,0 +1,85 @@
+import { GoabBadge, GoabCallout, GoabTable, GoabText } from "@abgov/react-components";
+
+export function TaskListPage() {
+ return (
+ <>
+ Apply for a service
+
+ You have completed 1 of 3 sections.
+
+
+ 1. Before you start
+
+
+
+
+
+
+ 3. Schedule service
+
+ You need to complete the previous section before you can start this task.
+
+
+
+
+
Receive email confirmation
+
+
+
+
+
+
Pay service fee
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/task-list-page/web-components.html b/docs/src/content/examples/task-list-page/web-components.html
new file mode 100644
index 0000000000..8391e985e5
--- /dev/null
+++ b/docs/src/content/examples/task-list-page/web-components.html
@@ -0,0 +1,65 @@
+Apply for a service
+
+ You have completed 1 of 3 sections.
+
+
+1. Before you start
+
+
+ Add
+
+
+
+
+
diff --git a/docs/src/content/examples/warn-a-user-of-a-deadline/angular.html b/docs/src/content/examples/warn-a-user-of-a-deadline/angular.html
new file mode 100644
index 0000000000..379c995d96
--- /dev/null
+++ b/docs/src/content/examples/warn-a-user-of-a-deadline/angular.html
@@ -0,0 +1,18 @@
+Save for later
+
+
+ You've selected to adjourn a matter that is required to appear today. This Calgary court
+ location does not accept adjournment requests past 1PM MST. Please submit your adjournment
+ request as soon as possible.
+
+
+
+ I understand
+
+
+
diff --git a/docs/src/content/examples/warn-a-user-of-a-deadline/angular.ts b/docs/src/content/examples/warn-a-user-of-a-deadline/angular.ts
new file mode 100644
index 0000000000..2ebceb6b1f
--- /dev/null
+++ b/docs/src/content/examples/warn-a-user-of-a-deadline/angular.ts
@@ -0,0 +1,13 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-warn-a-user-of-a-deadline",
+ templateUrl: "./angular.html",
+})
+export class WarnAUserOfADeadlineComponent {
+ open = false;
+
+ toggleModal(): void {
+ this.open = !this.open;
+ }
+}
diff --git a/docs/src/content/examples/warn-a-user-of-a-deadline/index.mdx b/docs/src/content/examples/warn-a-user-of-a-deadline/index.mdx
new file mode 100644
index 0000000000..a914aa1e17
--- /dev/null
+++ b/docs/src/content/examples/warn-a-user-of-a-deadline/index.mdx
@@ -0,0 +1,35 @@
+---
+id: warn-a-user-of-a-deadline
+title: Warn a user of a deadline
+categories:
+ - feedback-and-alerts
+scale: task
+userType: both
+tags:
+ - modal
+ - warning
+ - deadline
+ - callout
+components:
+ - modal
+ - button
+ - button-group
+status: published
+---
+
+Use a modal with important callout styling to warn users about time-sensitive deadlines that could affect their submission or action.
+
+## When to use
+
+Use this pattern when:
+- Users are about to take an action with a time constraint
+- Missing a deadline could have significant consequences
+- The warning requires acknowledgment before proceeding
+
+## Considerations
+
+- Be specific about the deadline (time, date, timezone)
+- Explain the consequences of missing the deadline
+- Provide a clear acknowledgment action
+- Use the "important" callout variant for urgency
+- Keep the message concise but informative
diff --git a/docs/src/content/examples/warn-a-user-of-a-deadline/react.tsx b/docs/src/content/examples/warn-a-user-of-a-deadline/react.tsx
new file mode 100644
index 0000000000..e327817b09
--- /dev/null
+++ b/docs/src/content/examples/warn-a-user-of-a-deadline/react.tsx
@@ -0,0 +1,33 @@
+import { useState } from "react";
+import { GoabButton, GoabButtonGroup, GoabModal } from "@abgov/react-components";
+
+export function WarnAUserOfADeadline() {
+ const [open, setOpen] = useState(false);
+
+ return (
+ <>
+ setOpen(true)}>
+ Save for later
+
+ setOpen(false)}
+ actions={
+
+ setOpen(false)}>
+ I understand
+
+
+ }
+ >
+
+ You've selected to adjourn a matter that is required to appear today. This Calgary court
+ location does not accept adjournment requests past 1PM MST. Please submit your
+ adjournment request as soon as possible.
+
+
+ >
+ );
+}
diff --git a/docs/src/content/examples/warn-a-user-of-a-deadline/web-components.html b/docs/src/content/examples/warn-a-user-of-a-deadline/web-components.html
new file mode 100644
index 0000000000..c2786b3fae
--- /dev/null
+++ b/docs/src/content/examples/warn-a-user-of-a-deadline/web-components.html
@@ -0,0 +1,32 @@
+Save for later
+
+ You've selected to adjourn a matter that is required to appear today. This Calgary court
+ location does not accept adjournment requests past 1PM MST. Please submit your adjournment
+ request as soon as possible.
+
+
+ I understand
+
+
+
+
+
diff --git a/docs/src/content/guidance/accessible-icons-need-label.mdx b/docs/src/content/guidance/accessible-icons-need-label.mdx
new file mode 100644
index 0000000000..ea7df5147f
--- /dev/null
+++ b/docs/src/content/guidance/accessible-icons-need-label.mdx
@@ -0,0 +1,40 @@
+---
+id: accessible-icons-need-label
+type: dont
+description: Don't use icon-only elements without an accessible label
+topic: screen-readers
+tags:
+ - accessibility
+ - icons
+ - wcag
+appliesTo:
+ components:
+ - icon-button
+ - badge
+ - icon
+status: published
+---
+
+Icon-only interactive elements must have an accessible label so screen reader users understand their purpose.
+
+**For IconButton:** The `ariaLabel` prop is required.
+
+```jsx
+// Good - describes the action
+
+
+// Bad - no label for screen readers
+
+```
+
+**For Badge with icon only:** Provide `ariaLabel` when there's no visible text.
+
+```jsx
+
+```
+
+**For Icon:** Use `ariaLabel` when the icon conveys meaning, not just decoration.
+
+The label should describe:
+- What action happens (for buttons): "Delete", "Edit", "Close"
+- What the icon represents (for informational icons): "Warning", "Success"
diff --git a/docs/src/content/guidance/accordion-content-left-aligned.mdx b/docs/src/content/guidance/accordion-content-left-aligned.mdx
new file mode 100644
index 0000000000..d759f825ba
--- /dev/null
+++ b/docs/src/content/guidance/accordion-content-left-aligned.mdx
@@ -0,0 +1,20 @@
+---
+id: accordion-content-left-aligned
+type: do
+description: Ensure accordion content is left-aligned with the heading, leaving white space on the left side of the container.
+topic: positioning
+tags:
+ - accordion
+ - alignment
+ - layout
+appliesTo:
+ components:
+ - accordion
+status: published
+---
+
+
+
+ Enter your full legal name as it appears on your government-issued ID.
+
+
diff --git a/docs/src/content/guidance/accordion-dont-hide-critical-content.mdx b/docs/src/content/guidance/accordion-dont-hide-critical-content.mdx
new file mode 100644
index 0000000000..242a1bf218
--- /dev/null
+++ b/docs/src/content/guidance/accordion-dont-hide-critical-content.mdx
@@ -0,0 +1,20 @@
+---
+id: accordion-dont-hide-critical-content
+type: dont
+description: Don't hide key functionality in collapsed accordions. If content is critical to the workflow, it should be visible when the page loads.
+topic: other
+tags:
+ - accordion
+ - usability
+ - content
+appliesTo:
+ components:
+ - accordion
+status: published
+---
+
+
+
+ Submit
+
+
diff --git a/docs/src/content/guidance/accordion-line-length.mdx b/docs/src/content/guidance/accordion-line-length.mdx
new file mode 100644
index 0000000000..c31130b872
--- /dev/null
+++ b/docs/src/content/guidance/accordion-line-length.mdx
@@ -0,0 +1,20 @@
+---
+id: accordion-line-length
+type: dont
+description: Don't exceed 75 characters in line length within expanded accordion content.
+topic: content
+tags:
+ - accordion
+ - readability
+ - content
+appliesTo:
+ components:
+ - accordion
+status: published
+---
+
+
+
+ Lorem ipsum dolor sit amet consectetur. Felis mauris in interdum congue amet curabitur diam enim. Sem nec ut sed tristique mauris nibh ac.
+
+
diff --git a/docs/src/content/guidance/accordion-secondary-text.mdx b/docs/src/content/guidance/accordion-secondary-text.mdx
new file mode 100644
index 0000000000..abd6588b20
--- /dev/null
+++ b/docs/src/content/guidance/accordion-secondary-text.mdx
@@ -0,0 +1,21 @@
+---
+id: accordion-secondary-text
+type: do
+description: Use secondaryText for contextual information in accordions
+topic: content
+tags:
+ - accordion
+ - content
+appliesTo:
+ components:
+ - accordion
+relatedProps:
+ - secondaryText
+status: published
+---
+
+
+
+ Content here
+
+
diff --git a/docs/src/content/guidance/badge-dont-primary-button-to-edit.mdx b/docs/src/content/guidance/badge-dont-primary-button-to-edit.mdx
new file mode 100644
index 0000000000..fa52dbe0da
--- /dev/null
+++ b/docs/src/content/guidance/badge-dont-primary-button-to-edit.mdx
@@ -0,0 +1,19 @@
+---
+id: badge-dont-primary-button-to-edit
+type: dont
+description: Don't use a primary button to edit a badge.
+topic: other
+tags:
+ - badge
+ - button
+ - interactivity
+appliesTo:
+ components:
+ - badge
+status: published
+---
+
+
+
+ Edit
+
diff --git a/docs/src/content/guidance/badge-dont-style-like-buttons.mdx b/docs/src/content/guidance/badge-dont-style-like-buttons.mdx
new file mode 100644
index 0000000000..2e61d2c357
--- /dev/null
+++ b/docs/src/content/guidance/badge-dont-style-like-buttons.mdx
@@ -0,0 +1,17 @@
+---
+id: badge-dont-style-like-buttons
+type: dont
+description: Don't style badges to look like buttons.
+topic: types
+tags:
+ - badge
+ - styling
+appliesTo:
+ components:
+ - badge
+status: published
+---
+
+
+
+
diff --git a/docs/src/content/guidance/badge-dont-use-interactive-colours.mdx b/docs/src/content/guidance/badge-dont-use-interactive-colours.mdx
new file mode 100644
index 0000000000..5b9d8aa559
--- /dev/null
+++ b/docs/src/content/guidance/badge-dont-use-interactive-colours.mdx
@@ -0,0 +1,18 @@
+---
+id: badge-dont-use-interactive-colours
+type: dont
+description: Don't use interactive colours. These are reserved for links, buttons, and other interactive elements.
+topic: types
+tags:
+ - badge
+ - colours
+ - accessibility
+appliesTo:
+ components:
+ - badge
+status: published
+---
+
+
+
+
diff --git a/docs/src/content/guidance/badge-for-information-not-interaction.mdx b/docs/src/content/guidance/badge-for-information-not-interaction.mdx
new file mode 100644
index 0000000000..de35dafd66
--- /dev/null
+++ b/docs/src/content/guidance/badge-for-information-not-interaction.mdx
@@ -0,0 +1,18 @@
+---
+id: badge-for-information-not-interaction
+type: do
+description: Use badges for information and organization, not interactivity.
+topic: other
+tags:
+ - badge
+ - usage
+appliesTo:
+ components:
+ - badge
+status: published
+---
+
+
+
+
+
diff --git a/docs/src/content/guidance/badge-sentence-case.mdx b/docs/src/content/guidance/badge-sentence-case.mdx
new file mode 100644
index 0000000000..20366bcff7
--- /dev/null
+++ b/docs/src/content/guidance/badge-sentence-case.mdx
@@ -0,0 +1,18 @@
+---
+id: badge-sentence-case
+type: do
+description: Use sentence case for badge text. Capitalize the first word only.
+topic: content
+tags:
+ - badge
+ - content
+ - casing
+appliesTo:
+ components:
+ - badge
+status: published
+---
+
+
+
+
diff --git a/docs/src/content/guidance/badge-short-text.mdx b/docs/src/content/guidance/badge-short-text.mdx
new file mode 100644
index 0000000000..b44615265e
--- /dev/null
+++ b/docs/src/content/guidance/badge-short-text.mdx
@@ -0,0 +1,17 @@
+---
+id: badge-short-text
+type: do
+description: Use short, concise text in badges.
+topic: content
+tags:
+ - badge
+ - content
+appliesTo:
+ components:
+ - badge
+status: published
+---
+
+
+
+
diff --git a/docs/src/content/guidance/badge-tertiary-button-to-edit.mdx b/docs/src/content/guidance/badge-tertiary-button-to-edit.mdx
new file mode 100644
index 0000000000..ab8d5cfa01
--- /dev/null
+++ b/docs/src/content/guidance/badge-tertiary-button-to-edit.mdx
@@ -0,0 +1,19 @@
+---
+id: badge-tertiary-button-to-edit
+type: do
+description: Use a tertiary button next to a badge if it needs to be manually updated.
+topic: other
+tags:
+ - badge
+ - button
+ - interactivity
+appliesTo:
+ components:
+ - badge
+status: published
+---
+
+
+
+ Edit
+
diff --git a/docs/src/content/guidance/badge-types.mdx b/docs/src/content/guidance/badge-types.mdx
new file mode 100644
index 0000000000..a7c1b492ac
--- /dev/null
+++ b/docs/src/content/guidance/badge-types.mdx
@@ -0,0 +1,25 @@
+---
+id: badge-types
+type: do
+description: Match badge type to the status it represents
+topic: types
+tags:
+ - badge
+ - status
+ - feedback
+appliesTo:
+ components:
+ - badge
+relatedProps:
+ - type
+status: published
+---
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/button-avoid-disabled.mdx b/docs/src/content/guidance/button-avoid-disabled.mdx
new file mode 100644
index 0000000000..a77d318299
--- /dev/null
+++ b/docs/src/content/guidance/button-avoid-disabled.mdx
@@ -0,0 +1,26 @@
+---
+id: button-avoid-disabled
+type: dont
+description: Avoid using disabled buttons. They have poor contrast and can confuse users.
+topic: states
+tags:
+ - button
+ - disabled
+ - accessibility
+ - usability
+appliesTo:
+ components:
+ - button
+ - icon-button
+relatedProps:
+ - disabled
+status: published
+---
+
+
+ Submit
+
+
+Only use disabled buttons if research shows it makes the user interface easier to understand.
+
+Consider removing options that are unavailable or not applicable. Show actions that are only relevant and useful to the user at a given time.
diff --git a/docs/src/content/guidance/button-compact-for-dense-spaces.mdx b/docs/src/content/guidance/button-compact-for-dense-spaces.mdx
new file mode 100644
index 0000000000..c01bdb3718
--- /dev/null
+++ b/docs/src/content/guidance/button-compact-for-dense-spaces.mdx
@@ -0,0 +1,21 @@
+---
+id: button-compact-for-dense-spaces
+type: do
+description: Use compact buttons in dense spaces like tables or container title bars.
+topic: sizing
+tags:
+ - button
+ - compact
+ - sizing
+ - table
+appliesTo:
+ components:
+ - button
+relatedProps:
+ - size
+status: published
+---
+
+
+ Edit
+
diff --git a/docs/src/content/guidance/button-concise-labels.mdx b/docs/src/content/guidance/button-concise-labels.mdx
new file mode 100644
index 0000000000..7d327b1c33
--- /dev/null
+++ b/docs/src/content/guidance/button-concise-labels.mdx
@@ -0,0 +1,19 @@
+---
+id: button-concise-labels
+type: do
+description: Use one word to explain the function whenever possible, such as "Save", "Submit", or "Search".
+topic: content
+tags:
+ - button
+ - content
+ - labeling
+appliesTo:
+ components:
+ - button
+status: published
+---
+
+
+ Submit
+ Cancel
+
diff --git a/docs/src/content/guidance/button-consistent-sizes.mdx b/docs/src/content/guidance/button-consistent-sizes.mdx
new file mode 100644
index 0000000000..22800ac55f
--- /dev/null
+++ b/docs/src/content/guidance/button-consistent-sizes.mdx
@@ -0,0 +1,23 @@
+---
+id: button-consistent-sizes
+type: dont
+description: Don't use different button sizes in the same area to emphasize hierarchy.
+topic: sizing
+tags:
+ - button
+ - sizing
+ - hierarchy
+ - consistency
+appliesTo:
+ components:
+ - button
+ - button-group
+relatedProps:
+ - size
+status: published
+---
+
+
+ Save
+ Cancel
+
diff --git a/docs/src/content/guidance/button-consistent-widths.mdx b/docs/src/content/guidance/button-consistent-widths.mdx
new file mode 100644
index 0000000000..00375f5f1e
--- /dev/null
+++ b/docs/src/content/guidance/button-consistent-widths.mdx
@@ -0,0 +1,25 @@
+---
+id: button-consistent-widths
+type: dont
+description: Don't stack standard and full width buttons.
+topic: sizing
+tags:
+ - button
+ - sizing
+ - consistency
+ - mobile
+appliesTo:
+ components:
+ - button
+ - button-group
+relatedProps:
+ - width
+status: published
+---
+
+
+
+ Cancel
+ Save
+
+
diff --git a/docs/src/content/guidance/button-destructive-descriptive-language.mdx b/docs/src/content/guidance/button-destructive-descriptive-language.mdx
new file mode 100644
index 0000000000..2fc5b225ab
--- /dev/null
+++ b/docs/src/content/guidance/button-destructive-descriptive-language.mdx
@@ -0,0 +1,23 @@
+---
+id: button-destructive-descriptive-language
+type: do
+description: Use descriptive language in both modal content and button text to inform users of the resulting destructive action.
+topic: content
+tags:
+ - button
+ - destructive
+ - modal
+ - content
+ - labeling
+appliesTo:
+ components:
+ - button
+ - modal
+relatedProps:
+ - variant
+status: published
+---
+
+
+ Cancel application
+
diff --git a/docs/src/content/guidance/button-destructive-for-irreversible.mdx b/docs/src/content/guidance/button-destructive-for-irreversible.mdx
new file mode 100644
index 0000000000..9121c86c00
--- /dev/null
+++ b/docs/src/content/guidance/button-destructive-for-irreversible.mdx
@@ -0,0 +1,21 @@
+---
+id: button-destructive-for-irreversible
+type: do
+description: Use the destructive button variant for actions that cannot be easily undone, like permanently deleting data or removing a user from a system.
+topic: types
+tags:
+ - button
+ - destructive
+ - safety
+appliesTo:
+ components:
+ - button
+ - modal
+relatedProps:
+ - variant
+status: published
+---
+
+
+ Delete account
+
diff --git a/docs/src/content/guidance/button-destructive-only-final-action.mdx b/docs/src/content/guidance/button-destructive-only-final-action.mdx
new file mode 100644
index 0000000000..be6e1ffb1b
--- /dev/null
+++ b/docs/src/content/guidance/button-destructive-only-final-action.mdx
@@ -0,0 +1,22 @@
+---
+id: button-destructive-only-final-action
+type: dont
+description: Don't use a destructive button to trigger a confirmation. Reserve destructive styling for the final action inside the modal.
+topic: types
+tags:
+ - button
+ - destructive
+ - modal
+ - confirmation
+appliesTo:
+ components:
+ - button
+ - modal
+relatedProps:
+ - variant
+status: published
+---
+
+
+ Delete record
+
diff --git a/docs/src/content/guidance/button-dont-read-icon-class.mdx b/docs/src/content/guidance/button-dont-read-icon-class.mdx
new file mode 100644
index 0000000000..29b09abba0
--- /dev/null
+++ b/docs/src/content/guidance/button-dont-read-icon-class.mdx
@@ -0,0 +1,20 @@
+---
+id: button-dont-read-icon-class
+type: dont
+description: Don't read the icon class or description for icon buttons with labels. Screen readers should read the button label only.
+topic: screen-readers
+tags:
+ - button
+ - accessibility
+ - screen-readers
+ - icons
+appliesTo:
+ components:
+ - button
+relatedProps:
+ - leadingIcon
+ - trailingIcon
+status: published
+---
+
+For icon buttons with both a label and icon, hide the icon from the screen reader so it announces "Button, add row" not "Button, cross icon, add row".
diff --git a/docs/src/content/guidance/button-enabled-with-error-handling.mdx b/docs/src/content/guidance/button-enabled-with-error-handling.mdx
new file mode 100644
index 0000000000..4bef370591
--- /dev/null
+++ b/docs/src/content/guidance/button-enabled-with-error-handling.mdx
@@ -0,0 +1,19 @@
+---
+id: button-enabled-with-error-handling
+type: do
+description: Keep buttons enabled and use error handling to provide clear feedback when the user submits.
+topic: states
+tags:
+ - button
+ - validation
+ - error-handling
+ - forms
+appliesTo:
+ components:
+ - button
+relatedProps:
+ - disabled
+status: published
+---
+
+Instead of disabling a submit button, keep it enabled and provide clear feedback about any missed fields or input errors when the user tries to submit the form.
diff --git a/docs/src/content/guidance/button-focus-whole-button.mdx b/docs/src/content/guidance/button-focus-whole-button.mdx
new file mode 100644
index 0000000000..1a319bf816
--- /dev/null
+++ b/docs/src/content/guidance/button-focus-whole-button.mdx
@@ -0,0 +1,16 @@
+---
+id: button-focus-whole-button
+type: dont
+description: Don't focus on just the icon within a button. Focus the button as a whole.
+topic: focus
+tags:
+ - button
+ - accessibility
+ - focus
+ - icons
+appliesTo:
+ components:
+ - button
+ - icon-button
+status: published
+---
diff --git a/docs/src/content/guidance/button-full-width-mobile.mdx b/docs/src/content/guidance/button-full-width-mobile.mdx
new file mode 100644
index 0000000000..c34acb67ea
--- /dev/null
+++ b/docs/src/content/guidance/button-full-width-mobile.mdx
@@ -0,0 +1,25 @@
+---
+id: button-full-width-mobile
+type: do
+description: Use full width buttons on mobile.
+topic: sizing
+tags:
+ - button
+ - mobile
+ - responsive
+ - sizing
+appliesTo:
+ components:
+ - button
+ - button-group
+relatedProps:
+ - width
+status: published
+---
+
+
+
+ Save
+ Cancel
+
+
diff --git a/docs/src/content/guidance/button-icon-clear-association.mdx b/docs/src/content/guidance/button-icon-clear-association.mdx
new file mode 100644
index 0000000000..4ad95ea4f9
--- /dev/null
+++ b/docs/src/content/guidance/button-icon-clear-association.mdx
@@ -0,0 +1,21 @@
+---
+id: button-icon-clear-association
+type: do
+description: Use icons with a clear visual association to the action.
+topic: icons
+tags:
+ - button
+ - icons
+ - clarity
+appliesTo:
+ components:
+ - button
+relatedProps:
+ - leadingIcon
+ - trailingIcon
+status: published
+---
+
+
+ Add item
+
diff --git a/docs/src/content/guidance/button-icon-no-unclear-association.mdx b/docs/src/content/guidance/button-icon-no-unclear-association.mdx
new file mode 100644
index 0000000000..c637ebf881
--- /dev/null
+++ b/docs/src/content/guidance/button-icon-no-unclear-association.mdx
@@ -0,0 +1,21 @@
+---
+id: button-icon-no-unclear-association
+type: dont
+description: Don't use icons that don't have a clear visual association to the intended outcome.
+topic: icons
+tags:
+ - button
+ - icons
+ - clarity
+appliesTo:
+ components:
+ - button
+relatedProps:
+ - leadingIcon
+ - trailingIcon
+status: published
+---
+
+
+ Confirm
+
diff --git a/docs/src/content/guidance/button-icon-only-needs-label.mdx b/docs/src/content/guidance/button-icon-only-needs-label.mdx
new file mode 100644
index 0000000000..b21a794ec4
--- /dev/null
+++ b/docs/src/content/guidance/button-icon-only-needs-label.mdx
@@ -0,0 +1,22 @@
+---
+id: button-icon-only-needs-label
+type: do
+description: Icon-only buttons must include a descriptive label for screen readers.
+topic: screen-readers
+tags:
+ - button
+ - accessibility
+ - screen-readers
+ - icons
+appliesTo:
+ components:
+ - button
+ - icon-button
+relatedProps:
+ - ariaLabel
+status: published
+---
+
+
+
+
diff --git a/docs/src/content/guidance/button-icon-with-text-label.mdx b/docs/src/content/guidance/button-icon-with-text-label.mdx
new file mode 100644
index 0000000000..f8ef548c08
--- /dev/null
+++ b/docs/src/content/guidance/button-icon-with-text-label.mdx
@@ -0,0 +1,22 @@
+---
+id: button-icon-with-text-label
+type: do
+description: Use a text label with an icon, especially for public-facing applications and novice users.
+topic: icons
+tags:
+ - button
+ - icons
+ - accessibility
+ - labeling
+appliesTo:
+ components:
+ - button
+relatedProps:
+ - leadingIcon
+ - trailingIcon
+status: published
+---
+
+
+ Add new
+
diff --git a/docs/src/content/guidance/button-limit-grouped-actions.mdx b/docs/src/content/guidance/button-limit-grouped-actions.mdx
new file mode 100644
index 0000000000..f2602a97ae
--- /dev/null
+++ b/docs/src/content/guidance/button-limit-grouped-actions.mdx
@@ -0,0 +1,24 @@
+---
+id: button-limit-grouped-actions
+type: dont
+description: Don't group more than 3 actions together. Consider using an overflow menu for additional options.
+topic: positioning
+tags:
+ - button
+ - button-group
+ - overflow
+ - actions
+appliesTo:
+ components:
+ - button
+ - button-group
+status: published
+---
+
+
+ Submit
+ Edit
+ Save
+ Copy
+ Draft
+
diff --git a/docs/src/content/guidance/button-one-primary-per-page.mdx b/docs/src/content/guidance/button-one-primary-per-page.mdx
new file mode 100644
index 0000000000..012e441521
--- /dev/null
+++ b/docs/src/content/guidance/button-one-primary-per-page.mdx
@@ -0,0 +1,22 @@
+---
+id: button-one-primary-per-page
+type: dont
+description: Avoid using more than one primary button per page. Multiple primary buttons create visual competition and make it unclear which action is most important.
+topic: types
+tags:
+ - button
+ - hierarchy
+ - visual-weight
+appliesTo:
+ components:
+ - button
+relatedProps:
+ - type
+status: published
+---
+
+
+ Save
+ Submit
+ Continue
+
diff --git a/docs/src/content/guidance/button-primary-secondary-pairing.mdx b/docs/src/content/guidance/button-primary-secondary-pairing.mdx
new file mode 100644
index 0000000000..6df057a78a
--- /dev/null
+++ b/docs/src/content/guidance/button-primary-secondary-pairing.mdx
@@ -0,0 +1,22 @@
+---
+id: button-primary-secondary-pairing
+type: do
+description: Use a primary button for main actions and a secondary button for less important actions.
+topic: types
+tags:
+ - button
+ - hierarchy
+ - types
+appliesTo:
+ components:
+ - button
+ - button-group
+relatedProps:
+ - type
+status: published
+---
+
+
+ Save
+ Cancel
+
diff --git a/docs/src/content/guidance/button-sentence-case.mdx b/docs/src/content/guidance/button-sentence-case.mdx
new file mode 100644
index 0000000000..989e4fc764
--- /dev/null
+++ b/docs/src/content/guidance/button-sentence-case.mdx
@@ -0,0 +1,20 @@
+---
+id: button-sentence-case
+type: dont
+description: Don't use all uppercase or all lowercase to label buttons.
+topic: content
+tags:
+ - button
+ - content
+ - labeling
+ - casing
+appliesTo:
+ components:
+ - button
+status: published
+---
+
+
+ SUBMIT
+ cancel
+
diff --git a/docs/src/content/guidance/button-types-overview.mdx b/docs/src/content/guidance/button-types-overview.mdx
new file mode 100644
index 0000000000..20a42f066b
--- /dev/null
+++ b/docs/src/content/guidance/button-types-overview.mdx
@@ -0,0 +1,19 @@
+---
+id: button-types-overview
+type: info
+description: Button types
+topic: types
+tags:
+ - button
+ - types
+ - hierarchy
+appliesTo:
+ components:
+ - button
+ - button-group
+status: published
+---
+
+- **Primary** - If there is only one button on a page, it should be a primary button. For citizen facing applications, generally there should only be one primary button on a page.
+- **Secondary** - Use secondary buttons for less important actions on a page. Often paired with a primary action as a secondary action.
+- **Tertiary** - Use tertiary buttons for links that should function like a button, such as "edit" or "cancel" in applications. It's okay to use more than one tertiary button on a page.
diff --git a/docs/src/content/guidance/button-use-clear-action-labels.mdx b/docs/src/content/guidance/button-use-clear-action-labels.mdx
new file mode 100644
index 0000000000..54e4a402df
--- /dev/null
+++ b/docs/src/content/guidance/button-use-clear-action-labels.mdx
@@ -0,0 +1,22 @@
+---
+id: button-use-clear-action-labels
+type: do
+description: Button labels should clearly describe what happens when clicked. Use specific verbs like "Submit application" or "Save draft" instead of generic labels like "OK" or "Click here".
+topic: content
+tags:
+ - button
+ - content
+ - labeling
+appliesTo:
+ components:
+ - button
+status: published
+---
+
+
+
+ Submit application
+ Save draft
+ Cancel
+
+
diff --git a/docs/src/content/guidance/button-vs-link.mdx b/docs/src/content/guidance/button-vs-link.mdx
new file mode 100644
index 0000000000..ebb891f2aa
--- /dev/null
+++ b/docs/src/content/guidance/button-vs-link.mdx
@@ -0,0 +1,22 @@
+---
+id: button-vs-link
+type: do
+description: Use a button for actions that trigger functionality (submit, save, cancel). Use a link for navigation to different pages or external websites.
+topic: types
+tags:
+ - button
+ - link
+ - navigation
+ - semantics
+appliesTo:
+ components:
+ - button
+ - link
+status: published
+---
+
+
+ Submit form
+
+
+This distinction matters for screen reader users who expect different behaviors, keyboard navigation patterns, and browser history.
diff --git a/docs/src/content/guidance/button-when-not-to-use.mdx b/docs/src/content/guidance/button-when-not-to-use.mdx
new file mode 100644
index 0000000000..2ba7e640b4
--- /dev/null
+++ b/docs/src/content/guidance/button-when-not-to-use.mdx
@@ -0,0 +1,20 @@
+---
+id: button-when-not-to-use
+type: dont
+description: Don't use Button for simple navigation (use Link), toggling state (use Toggle or Checkbox), or minor utility functions (use Icon Button).
+topic: types
+tags:
+ - button
+ - usage
+appliesTo:
+ components:
+ - button
+ - link
+ - checkbox
+ - icon-button
+status: published
+---
+
+
+ Go to homepage
+
diff --git a/docs/src/content/guidance/button-when-to-use.mdx b/docs/src/content/guidance/button-when-to-use.mdx
new file mode 100644
index 0000000000..9e963c5b22
--- /dev/null
+++ b/docs/src/content/guidance/button-when-to-use.mdx
@@ -0,0 +1,17 @@
+---
+id: button-when-to-use
+type: do
+description: Use a button when you need users to take a specific action, such as submitting a form, starting a process, or confirming a decision.
+topic: types
+tags:
+ - button
+ - usage
+appliesTo:
+ components:
+ - button
+status: published
+---
+
+
+ Submit application
+
diff --git a/docs/src/content/guidance/buttongroup-alignment.mdx b/docs/src/content/guidance/buttongroup-alignment.mdx
new file mode 100644
index 0000000000..42396f27a6
--- /dev/null
+++ b/docs/src/content/guidance/buttongroup-alignment.mdx
@@ -0,0 +1,22 @@
+---
+id: buttongroup-alignment
+type: do
+description: Use a button group when putting multiple buttons together.
+topic: positioning
+tags:
+ - button-group
+ - layout
+appliesTo:
+ components:
+ - button-group
+ - button
+ - icon-button
+status: published
+---
+
+
+
+ Submit
+ Cancel
+
+
diff --git a/docs/src/content/guidance/callout-full-width.mdx b/docs/src/content/guidance/callout-full-width.mdx
new file mode 100644
index 0000000000..18e3768e31
--- /dev/null
+++ b/docs/src/content/guidance/callout-full-width.mdx
@@ -0,0 +1,20 @@
+---
+id: callout-full-width
+type: do
+description: Use full width callouts with a maximum width of 700px.
+topic: sizing
+tags:
+ - callout
+ - layout
+ - width
+appliesTo:
+ components:
+ - callout
+status: published
+---
+
+
+
+ Provincial Family Resource Networks deliver high quality prevention and early intervention services.
+
+
diff --git a/docs/src/content/guidance/callout-inline-links.mdx b/docs/src/content/guidance/callout-inline-links.mdx
new file mode 100644
index 0000000000..7aa918472f
--- /dev/null
+++ b/docs/src/content/guidance/callout-inline-links.mdx
@@ -0,0 +1,20 @@
+---
+id: callout-inline-links
+type: do
+description: Use inline links when additional information exists on another page.
+topic: content
+tags:
+ - callout
+ - links
+ - content
+appliesTo:
+ components:
+ - callout
+status: published
+---
+
+
+
+ Networks deliver high quality prevention and early intervention services. Find a network in your area.
+
+
diff --git a/docs/src/content/guidance/callout-medium-on-mobile.mdx b/docs/src/content/guidance/callout-medium-on-mobile.mdx
new file mode 100644
index 0000000000..9917b248e2
--- /dev/null
+++ b/docs/src/content/guidance/callout-medium-on-mobile.mdx
@@ -0,0 +1,22 @@
+---
+id: callout-medium-on-mobile
+type: do
+description: Use the medium callout on mobile to save space.
+topic: sizing
+tags:
+ - callout
+ - mobile
+ - responsive
+appliesTo:
+ components:
+ - callout
+relatedProps:
+ - size
+status: published
+---
+
+
+
+ This callout uses the medium size for mobile viewports.
+
+
diff --git a/docs/src/content/guidance/callout-not-dismissible.mdx b/docs/src/content/guidance/callout-not-dismissible.mdx
new file mode 100644
index 0000000000..31dc6f8a47
--- /dev/null
+++ b/docs/src/content/guidance/callout-not-dismissible.mdx
@@ -0,0 +1,19 @@
+---
+id: callout-not-dismissible
+type: dont
+description: Don't allow callouts to be dismissed.
+topic: other
+tags:
+ - callout
+ - interactivity
+appliesTo:
+ components:
+ - callout
+status: published
+---
+
+
+
+ Changes to employment standards rules are in effect.
+
+
diff --git a/docs/src/content/guidance/callout-not-for-validation.mdx b/docs/src/content/guidance/callout-not-for-validation.mdx
new file mode 100644
index 0000000000..283a651430
--- /dev/null
+++ b/docs/src/content/guidance/callout-not-for-validation.mdx
@@ -0,0 +1,20 @@
+---
+id: callout-not-for-validation
+type: dont
+description: Don't use callouts for form or field validation. Use error messages instead.
+topic: other
+tags:
+ - callout
+ - validation
+ - forms
+appliesTo:
+ components:
+ - callout
+status: published
+---
+
+
+
+ The username you entered did not match our records.
+
+
diff --git a/docs/src/content/guidance/callout-one-piece-of-info.mdx b/docs/src/content/guidance/callout-one-piece-of-info.mdx
new file mode 100644
index 0000000000..f6f27902fa
--- /dev/null
+++ b/docs/src/content/guidance/callout-one-piece-of-info.mdx
@@ -0,0 +1,19 @@
+---
+id: callout-one-piece-of-info
+type: dont
+description: Don't include too much content. Callouts should communicate one important piece of information.
+topic: content
+tags:
+ - callout
+ - content
+appliesTo:
+ components:
+ - callout
+status: published
+---
+
+
+
+ Employment standards set out the rights and obligations of employers and employees in Alberta. This includes the minimum standards that employers must provide. In this section, find out about Alberta's basic employment standards, what to do if you think they are not being followed, and educational materials.
+
+
diff --git a/docs/src/content/guidance/callout-usage.mdx b/docs/src/content/guidance/callout-usage.mdx
new file mode 100644
index 0000000000..cb6bf7c084
--- /dev/null
+++ b/docs/src/content/guidance/callout-usage.mdx
@@ -0,0 +1,20 @@
+---
+id: callout-usage
+type: do
+description: Keep callouts focused on one key message
+topic: content
+tags:
+ - callout
+ - content
+ - feedback
+appliesTo:
+ components:
+ - callout
+status: published
+---
+
+
+
+ Submit your application by March 31, 2024 to be considered.
+
+
diff --git a/docs/src/content/guidance/checkbox-capitalize-labels.mdx b/docs/src/content/guidance/checkbox-capitalize-labels.mdx
new file mode 100644
index 0000000000..2b2600addd
--- /dev/null
+++ b/docs/src/content/guidance/checkbox-capitalize-labels.mdx
@@ -0,0 +1,22 @@
+---
+id: checkbox-capitalize-labels
+type: do
+description: Start all checkbox labels with a capital letter.
+topic: content
+tags:
+ - checkbox
+ - content
+ - casing
+appliesTo:
+ components:
+ - checkbox
+status: published
+---
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/checkbox-for-multiple-selection.mdx b/docs/src/content/guidance/checkbox-for-multiple-selection.mdx
new file mode 100644
index 0000000000..28f191fa70
--- /dev/null
+++ b/docs/src/content/guidance/checkbox-for-multiple-selection.mdx
@@ -0,0 +1,20 @@
+---
+id: checkbox-for-multiple-selection
+type: do
+description: Use checkboxes when the user can select more than one option.
+topic: other
+tags:
+ - checkbox
+ - usage
+ - forms
+appliesTo:
+ components:
+ - checkbox
+status: published
+---
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/checkbox-left-of-label.mdx b/docs/src/content/guidance/checkbox-left-of-label.mdx
new file mode 100644
index 0000000000..f6b2c72d05
--- /dev/null
+++ b/docs/src/content/guidance/checkbox-left-of-label.mdx
@@ -0,0 +1,17 @@
+---
+id: checkbox-left-of-label
+type: do
+description: Put the checkbox input to the left of the label.
+topic: positioning
+tags:
+ - checkbox
+ - layout
+appliesTo:
+ components:
+ - checkbox
+status: published
+---
+
+
+
+
diff --git a/docs/src/content/guidance/checkbox-list-vertically.mdx b/docs/src/content/guidance/checkbox-list-vertically.mdx
new file mode 100644
index 0000000000..9e6edb5521
--- /dev/null
+++ b/docs/src/content/guidance/checkbox-list-vertically.mdx
@@ -0,0 +1,21 @@
+---
+id: checkbox-list-vertically
+type: do
+description: List checkbox options vertically.
+topic: positioning
+tags:
+ - checkbox
+ - layout
+appliesTo:
+ components:
+ - checkbox
+status: published
+---
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/checkbox-no-punctuation.mdx b/docs/src/content/guidance/checkbox-no-punctuation.mdx
new file mode 100644
index 0000000000..801edae89c
--- /dev/null
+++ b/docs/src/content/guidance/checkbox-no-punctuation.mdx
@@ -0,0 +1,21 @@
+---
+id: checkbox-no-punctuation
+type: dont
+description: Don't include punctuation after checkbox labels.
+topic: content
+tags:
+ - checkbox
+ - content
+appliesTo:
+ components:
+ - checkbox
+status: published
+---
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/checkbox-not-horizontal.mdx b/docs/src/content/guidance/checkbox-not-horizontal.mdx
new file mode 100644
index 0000000000..a33529740b
--- /dev/null
+++ b/docs/src/content/guidance/checkbox-not-horizontal.mdx
@@ -0,0 +1,21 @@
+---
+id: checkbox-not-horizontal
+type: dont
+description: Don't list options horizontally when showing more than two options.
+topic: positioning
+tags:
+ - checkbox
+ - layout
+appliesTo:
+ components:
+ - checkbox
+status: published
+---
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/circular-progress-for-fullscreen.mdx b/docs/src/content/guidance/circular-progress-for-fullscreen.mdx
new file mode 100644
index 0000000000..551218a648
--- /dev/null
+++ b/docs/src/content/guidance/circular-progress-for-fullscreen.mdx
@@ -0,0 +1,23 @@
+---
+id: circular-progress-for-fullscreen
+type: do
+description: Choose the right loading indicator for your context.
+topic: other
+tags:
+ - loading
+ - progress
+ - feedback
+appliesTo:
+ components:
+ - circular-progress
+ - skeleton
+status: published
+---
+
+
+
+
+
+
+
+Use **CircularProgress** for page-level or blocking operations. Use **Skeleton** for content placeholders while loading.
diff --git a/docs/src/content/guidance/container-not-for-layout.mdx b/docs/src/content/guidance/container-not-for-layout.mdx
new file mode 100644
index 0000000000..aaa1eb133b
--- /dev/null
+++ b/docs/src/content/guidance/container-not-for-layout.mdx
@@ -0,0 +1,30 @@
+---
+id: container-not-for-layout
+type: dont
+description: Don't use a container for general page layout. Containers are for visual emphasis and grouping content.
+topic: other
+tags:
+ - container
+ - layout
+ - patterns
+appliesTo:
+ components:
+ - container
+ - block
+ - grid
+status: published
+---
+
+
+
+
+
Header section
+
+
+
Main content area
+
+
+
Footer section
+
+
+
diff --git a/docs/src/content/guidance/datagrid-attributes.mdx b/docs/src/content/guidance/datagrid-attributes.mdx
new file mode 100644
index 0000000000..d57146e589
--- /dev/null
+++ b/docs/src/content/guidance/datagrid-attributes.mdx
@@ -0,0 +1,27 @@
+---
+id: datagrid-attributes
+type: do
+description: Add data-grid attributes to rows and cells for keyboard navigation to work.
+topic: keyboard
+tags:
+ - data-grid
+ - keyboard
+ - accessibility
+appliesTo:
+ components:
+ - data-grid
+status: published
+---
+
+
+
+
+
First cell
+
Second cell
+
+
+
Third cell
+
Fourth cell
+
+
+
diff --git a/docs/src/content/guidance/datepicker-calendar-variant.mdx b/docs/src/content/guidance/datepicker-calendar-variant.mdx
new file mode 100644
index 0000000000..ab2db37658
--- /dev/null
+++ b/docs/src/content/guidance/datepicker-calendar-variant.mdx
@@ -0,0 +1,21 @@
+---
+id: datepicker-calendar-variant
+type: do
+description: Use the calendar date picker for selecting dates relative to today, or when seeing the day of week is helpful.
+topic: types
+tags:
+ - date-picker
+ - forms
+appliesTo:
+ components:
+ - date-picker
+relatedProps:
+ - variant
+status: published
+---
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/datepicker-indicate-unavailable.mdx b/docs/src/content/guidance/datepicker-indicate-unavailable.mdx
new file mode 100644
index 0000000000..4d4196ec97
--- /dev/null
+++ b/docs/src/content/guidance/datepicker-indicate-unavailable.mdx
@@ -0,0 +1,17 @@
+---
+id: datepicker-indicate-unavailable
+type: do
+description: Indicate unavailable dates to help users avoid invalid selections.
+topic: other
+tags:
+ - date-picker
+ - usability
+appliesTo:
+ components:
+ - date-picker
+status: published
+---
+
+
+
+
diff --git a/docs/src/content/guidance/datepicker-input-variant.mdx b/docs/src/content/guidance/datepicker-input-variant.mdx
new file mode 100644
index 0000000000..ff53ce7945
--- /dev/null
+++ b/docs/src/content/guidance/datepicker-input-variant.mdx
@@ -0,0 +1,21 @@
+---
+id: datepicker-input-variant
+type: do
+description: Use the input date picker for known dates far in the past or future, such as a birthday.
+topic: types
+tags:
+ - date-picker
+ - forms
+appliesTo:
+ components:
+ - date-picker
+relatedProps:
+ - variant
+status: published
+---
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/details-dont-stack.mdx b/docs/src/content/guidance/details-dont-stack.mdx
new file mode 100644
index 0000000000..e783c7d611
--- /dev/null
+++ b/docs/src/content/guidance/details-dont-stack.mdx
@@ -0,0 +1,23 @@
+---
+id: details-dont-stack
+type: dont
+description: Don't stack multiple details together. Use an accordion instead for sets of information.
+topic: other
+tags:
+ - details
+ - accordion
+ - usage
+appliesTo:
+ components:
+ - details
+status: published
+---
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/details-for-optional-content.mdx b/docs/src/content/guidance/details-for-optional-content.mdx
new file mode 100644
index 0000000000..8dc341b2da
--- /dev/null
+++ b/docs/src/content/guidance/details-for-optional-content.mdx
@@ -0,0 +1,20 @@
+---
+id: details-for-optional-content
+type: do
+description: Use details to show more information or to help the user make a decision.
+topic: content
+tags:
+ - details
+ - help
+ - disclosure
+appliesTo:
+ components:
+ - details
+status: published
+---
+
+
+
+
Acceptable documents include utility bills dated within 3 months, bank statements, or government correspondence.
+
+
diff --git a/docs/src/content/guidance/details-inline-in-forms.mdx b/docs/src/content/guidance/details-inline-in-forms.mdx
new file mode 100644
index 0000000000..5f613ab64f
--- /dev/null
+++ b/docs/src/content/guidance/details-inline-in-forms.mdx
@@ -0,0 +1,21 @@
+---
+id: details-inline-in-forms
+type: do
+description: Use details inline within a form to disclose more information as needed.
+topic: other
+tags:
+ - details
+ - forms
+ - usage
+appliesTo:
+ components:
+ - details
+status: published
+---
+
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/details-line-length.mdx b/docs/src/content/guidance/details-line-length.mdx
new file mode 100644
index 0000000000..056c82c387
--- /dev/null
+++ b/docs/src/content/guidance/details-line-length.mdx
@@ -0,0 +1,20 @@
+---
+id: details-line-length
+type: do
+description: Keep content within 50-75 characters for optimal line length.
+topic: content
+tags:
+ - details
+ - readability
+ - content
+appliesTo:
+ components:
+ - details
+status: published
+---
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Dui integer sagittis, quis felis eu viverra libero.
+
+
diff --git a/docs/src/content/guidance/dont-disable-without-explanation.mdx b/docs/src/content/guidance/dont-disable-without-explanation.mdx
new file mode 100644
index 0000000000..9dd53be57c
--- /dev/null
+++ b/docs/src/content/guidance/dont-disable-without-explanation.mdx
@@ -0,0 +1,35 @@
+---
+id: dont-disable-without-explanation
+type: dont
+description: Don't disable buttons or inputs without explaining why. Disabled controls can be confusing and users may not understand why they can't interact with an element.
+topic: states
+tags:
+ - accessibility
+ - usability
+ - disabled
+appliesTo:
+ components:
+ - button
+ - input
+ - text-area
+ - dropdown
+ - date-picker
+ - checkbox
+ - radio-group
+ - icon-button
+status: published
+---
+
+
+
+
+
+
+ Submit
+
+
+
+When you must disable a button or input:
+- Provide nearby text explaining what needs to happen first
+- Consider showing the element enabled with validation on submit instead
+- Use aria-describedby to link the disabled element to explanatory text
diff --git a/docs/src/content/guidance/dropdown-consistent-width.mdx b/docs/src/content/guidance/dropdown-consistent-width.mdx
new file mode 100644
index 0000000000..9e624d295d
--- /dev/null
+++ b/docs/src/content/guidance/dropdown-consistent-width.mdx
@@ -0,0 +1,22 @@
+---
+id: dropdown-consistent-width
+type: do
+description: Define dropdown widths based on the widest dropdown in the form.
+topic: sizing
+tags:
+ - dropdown
+ - forms
+ - layout
+appliesTo:
+ components:
+ - dropdown
+status: published
+---
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/dropdown-default-width.mdx b/docs/src/content/guidance/dropdown-default-width.mdx
new file mode 100644
index 0000000000..471814981b
--- /dev/null
+++ b/docs/src/content/guidance/dropdown-default-width.mdx
@@ -0,0 +1,34 @@
+---
+id: dropdown-default-width
+type: do
+description: Use the default width for dropdowns. The dropdown automatically sets its width based on the length of the options.
+topic: sizing
+tags:
+ - dropdown
+ - forms
+ - sizing
+appliesTo:
+ components:
+ - dropdown
+status: published
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/dropdown-dont-hide-below-viewport.mdx b/docs/src/content/guidance/dropdown-dont-hide-below-viewport.mdx
new file mode 100644
index 0000000000..14c6e25c93
--- /dev/null
+++ b/docs/src/content/guidance/dropdown-dont-hide-below-viewport.mdx
@@ -0,0 +1,18 @@
+---
+id: dropdown-dont-hide-below-viewport
+type: dont
+description: Don't allow the dropdown menu to hide below the viewport.
+topic: positioning
+tags:
+ - dropdown
+ - positioning
+ - usability
+appliesTo:
+ components:
+ - dropdown
+status: published
+---
+
+
+
+
diff --git a/docs/src/content/guidance/dropdown-dont-truncate-labels.mdx b/docs/src/content/guidance/dropdown-dont-truncate-labels.mdx
new file mode 100644
index 0000000000..bfc20ed626
--- /dev/null
+++ b/docs/src/content/guidance/dropdown-dont-truncate-labels.mdx
@@ -0,0 +1,18 @@
+---
+id: dropdown-dont-truncate-labels
+type: dont
+description: Don't truncate labels. Longer labels should wrap to the next line.
+topic: content
+tags:
+ - dropdown
+ - labels
+ - mobile
+appliesTo:
+ components:
+ - dropdown
+status: published
+---
+
+
+
+
diff --git a/docs/src/content/guidance/fileupload-pair-input-card.mdx b/docs/src/content/guidance/fileupload-pair-input-card.mdx
new file mode 100644
index 0000000000..ee8e810426
--- /dev/null
+++ b/docs/src/content/guidance/fileupload-pair-input-card.mdx
@@ -0,0 +1,22 @@
+---
+id: fileupload-pair-input-card
+type: do
+description: Use file upload input with file upload card for complete file upload experiences.
+topic: other
+tags:
+ - file-upload
+ - forms
+ - components
+appliesTo:
+ components:
+ - file-upload-input
+ - file-upload-card
+status: published
+---
+
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/fileuploader-helper-text.mdx b/docs/src/content/guidance/fileuploader-helper-text.mdx
new file mode 100644
index 0000000000..b20501cd28
--- /dev/null
+++ b/docs/src/content/guidance/fileuploader-helper-text.mdx
@@ -0,0 +1,18 @@
+---
+id: fileuploader-helper-text
+type: do
+description: Use additional helper text to provide instructions about accepted file types.
+topic: content
+tags:
+ - file-uploader
+ - helper-text
+ - forms
+appliesTo:
+ components:
+ - file-uploader
+status: published
+---
+
+
+
+
diff --git a/docs/src/content/guidance/fileuploader-show-max-size.mdx b/docs/src/content/guidance/fileuploader-show-max-size.mdx
new file mode 100644
index 0000000000..1877101e1a
--- /dev/null
+++ b/docs/src/content/guidance/fileuploader-show-max-size.mdx
@@ -0,0 +1,17 @@
+---
+id: fileuploader-show-max-size
+type: do
+description: Show maximum file size in the file drop zone.
+topic: content
+tags:
+ - file-uploader
+ - usability
+appliesTo:
+ components:
+ - file-uploader
+status: published
+---
+
+
+
+
diff --git a/docs/src/content/guidance/footer-dont-customize-links.mdx b/docs/src/content/guidance/footer-dont-customize-links.mdx
new file mode 100644
index 0000000000..1f633756d9
--- /dev/null
+++ b/docs/src/content/guidance/footer-dont-customize-links.mdx
@@ -0,0 +1,18 @@
+---
+id: footer-dont-customize-links
+type: dont
+description: Don't customize the links in the footer.
+topic: other
+tags:
+ - footer
+ - links
+ - styling
+appliesTo:
+ components:
+ - app-footer
+status: published
+---
+
+
+
+
diff --git a/docs/src/content/guidance/footer-no-white-space-below.mdx b/docs/src/content/guidance/footer-no-white-space-below.mdx
new file mode 100644
index 0000000000..9043955f64
--- /dev/null
+++ b/docs/src/content/guidance/footer-no-white-space-below.mdx
@@ -0,0 +1,17 @@
+---
+id: footer-no-white-space-below
+type: dont
+description: Don't show white space below the footer. Extend the footer background to the bottom of the page.
+topic: positioning
+tags:
+ - footer
+ - layout
+appliesTo:
+ components:
+ - app-footer
+status: published
+---
+
+
+
+
diff --git a/docs/src/content/guidance/form-inputs-require-formitem.mdx b/docs/src/content/guidance/form-inputs-require-formitem.mdx
new file mode 100644
index 0000000000..950d0b6a73
--- /dev/null
+++ b/docs/src/content/guidance/form-inputs-require-formitem.mdx
@@ -0,0 +1,29 @@
+---
+id: form-inputs-require-formitem
+type: do
+description: Use a form item wrapper on all inputs to add a label, helper text, error message, and more.
+topic: other
+tags:
+ - forms
+ - accessibility
+ - labeling
+appliesTo:
+ components:
+ - input
+ - text-area
+ - dropdown
+ - date-picker
+ - radio-group
+ - checkbox-list
+ - checkbox
+ - form-item
+status: published
+---
+
+
+
+
+
+
+
+The form item automatically associates the label with the input for screen readers, ensuring your form is accessible.
diff --git a/docs/src/content/guidance/herobanner-accessible-alt-text.mdx b/docs/src/content/guidance/herobanner-accessible-alt-text.mdx
new file mode 100644
index 0000000000..23e1b4c284
--- /dev/null
+++ b/docs/src/content/guidance/herobanner-accessible-alt-text.mdx
@@ -0,0 +1,20 @@
+---
+id: herobanner-accessible-alt-text
+type: do
+description: Ensure hero banner images are accessible by using descriptive alt text.
+topic: accessibility
+tags:
+ - hero-banner
+ - images
+ - accessibility
+appliesTo:
+ components:
+ - hero-banner
+status: published
+---
+
+
+
+ Resources are available to help Alberta entrepreneurs.
+
+
diff --git a/docs/src/content/guidance/herobanner-dont-cta-unless-homepage.mdx b/docs/src/content/guidance/herobanner-dont-cta-unless-homepage.mdx
new file mode 100644
index 0000000000..be53e1cc28
--- /dev/null
+++ b/docs/src/content/guidance/herobanner-dont-cta-unless-homepage.mdx
@@ -0,0 +1,20 @@
+---
+id: herobanner-dont-cta-unless-homepage
+type: dont
+description: Don't include a call-to-action link in a hero banner unless it is on the home page.
+topic: interaction
+tags:
+ - hero-banner
+ - links
+appliesTo:
+ components:
+ - hero-banner
+status: published
+---
+
+
+
+ Learn more about what we offer.
+ Contact us
+
+
diff --git a/docs/src/content/guidance/herobanner-dont-focal-point-edges.mdx b/docs/src/content/guidance/herobanner-dont-focal-point-edges.mdx
new file mode 100644
index 0000000000..8c55e44b4f
--- /dev/null
+++ b/docs/src/content/guidance/herobanner-dont-focal-point-edges.mdx
@@ -0,0 +1,19 @@
+---
+id: herobanner-dont-focal-point-edges
+type: dont
+description: Don't select photos with focal points at the edges, as text overlays the imagery.
+topic: content
+tags:
+ - hero-banner
+ - images
+appliesTo:
+ components:
+ - hero-banner
+status: published
+---
+
+
+
+ Resources are available to help Alberta entrepreneurs.
+
+
diff --git a/docs/src/content/guidance/herobanner-dont-uncropped-images.mdx b/docs/src/content/guidance/herobanner-dont-uncropped-images.mdx
new file mode 100644
index 0000000000..ba964b147b
--- /dev/null
+++ b/docs/src/content/guidance/herobanner-dont-uncropped-images.mdx
@@ -0,0 +1,19 @@
+---
+id: herobanner-dont-uncropped-images
+type: dont
+description: Don't use a photograph without first cropping and resizing to fit the hero banner.
+topic: content
+tags:
+ - hero-banner
+ - images
+appliesTo:
+ components:
+ - hero-banner
+status: published
+---
+
+
+
+ Resources are available to help Alberta entrepreneurs.
+
+
diff --git a/docs/src/content/guidance/herobanner-focal-point-center.mdx b/docs/src/content/guidance/herobanner-focal-point-center.mdx
new file mode 100644
index 0000000000..d91bac7ef7
--- /dev/null
+++ b/docs/src/content/guidance/herobanner-focal-point-center.mdx
@@ -0,0 +1,19 @@
+---
+id: herobanner-focal-point-center
+type: do
+description: Select photos that place the subject matter or focal point in the center.
+topic: content
+tags:
+ - hero-banner
+ - images
+appliesTo:
+ components:
+ - hero-banner
+status: published
+---
+
+
+
+ Resources are available to help Alberta entrepreneurs.
+
+
diff --git a/docs/src/content/guidance/herobanner-optimize-images.mdx b/docs/src/content/guidance/herobanner-optimize-images.mdx
new file mode 100644
index 0000000000..84b0d59620
--- /dev/null
+++ b/docs/src/content/guidance/herobanner-optimize-images.mdx
@@ -0,0 +1,20 @@
+---
+id: herobanner-optimize-images
+type: do
+description: Enable image optimization for desktop, tablet, and mobile to minimize loading times.
+topic: performance
+tags:
+ - hero-banner
+ - images
+ - performance
+appliesTo:
+ components:
+ - hero-banner
+status: published
+---
+
+
+
+ Resources are available to help Alberta entrepreneurs.
+
+
diff --git a/docs/src/content/guidance/iconbutton-dont-unclear-actions.mdx b/docs/src/content/guidance/iconbutton-dont-unclear-actions.mdx
new file mode 100644
index 0000000000..c311d660a8
--- /dev/null
+++ b/docs/src/content/guidance/iconbutton-dont-unclear-actions.mdx
@@ -0,0 +1,17 @@
+---
+id: iconbutton-dont-unclear-actions
+type: dont
+description: Don't use icon buttons for actions that are not easily understood.
+topic: usage
+tags:
+ - icon-button
+ - buttons
+appliesTo:
+ components:
+ - icon-button
+status: published
+---
+
+
+
+
diff --git a/docs/src/content/guidance/iconbutton-tooltip-for-clarity.mdx b/docs/src/content/guidance/iconbutton-tooltip-for-clarity.mdx
new file mode 100644
index 0000000000..0759b319c6
--- /dev/null
+++ b/docs/src/content/guidance/iconbutton-tooltip-for-clarity.mdx
@@ -0,0 +1,20 @@
+---
+id: iconbutton-tooltip-for-clarity
+type: do
+description: Use a tooltip to clearly indicate an icon button's function when there's no visible label.
+topic: accessibility
+tags:
+ - icon-button
+ - tooltip
+ - accessibility
+appliesTo:
+ components:
+ - icon-button
+status: published
+---
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/iconbutton-universal-actions.mdx b/docs/src/content/guidance/iconbutton-universal-actions.mdx
new file mode 100644
index 0000000000..0cfc0a7ae9
--- /dev/null
+++ b/docs/src/content/guidance/iconbutton-universal-actions.mdx
@@ -0,0 +1,17 @@
+---
+id: iconbutton-universal-actions
+type: do
+description: Use icon buttons for universal actions such as closing a modal window.
+topic: usage
+tags:
+ - icon-button
+ - buttons
+appliesTo:
+ components:
+ - icon-button
+status: published
+---
+
+
+
+
diff --git a/docs/src/content/guidance/input-appropriate-type.mdx b/docs/src/content/guidance/input-appropriate-type.mdx
new file mode 100644
index 0000000000..eca17a6aa1
--- /dev/null
+++ b/docs/src/content/guidance/input-appropriate-type.mdx
@@ -0,0 +1,30 @@
+---
+id: input-appropriate-type
+type: do
+description: Use the appropriate input type for your context to give a better experience.
+topic: types
+tags:
+ - input
+ - accessibility
+ - mobile
+appliesTo:
+ components:
+ - input
+relatedProps:
+ - type
+status: published
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/input-no-placeholder-as-label.mdx b/docs/src/content/guidance/input-no-placeholder-as-label.mdx
new file mode 100644
index 0000000000..d4fb15096a
--- /dev/null
+++ b/docs/src/content/guidance/input-no-placeholder-as-label.mdx
@@ -0,0 +1,27 @@
+---
+id: input-no-placeholder-as-label
+type: dont
+description: Don't use placeholder text as a label
+topic: content
+tags:
+ - input
+ - accessibility
+ - labeling
+ - forms
+appliesTo:
+ components:
+ - input
+ - textarea
+ - dropdown
+relatedProps:
+ - placeholder
+status: published
+---
+
+
+
+
+
+Placeholder text disappears when users start typing, leaving them without context for what the field is asking for.
+
+Always use a visible label above or beside the input field. Placeholder text can provide an example of the expected format, but should never be the only indication of what information is needed.
diff --git a/docs/src/content/guidance/input-width-required.mdx b/docs/src/content/guidance/input-width-required.mdx
new file mode 100644
index 0000000000..edb21e70a0
--- /dev/null
+++ b/docs/src/content/guidance/input-width-required.mdx
@@ -0,0 +1,32 @@
+---
+id: input-width-required
+type: do
+description: Size text inputs based on the expected content length to help users understand what information is needed.
+topic: sizing
+tags:
+ - input
+ - forms
+ - layout
+appliesTo:
+ components:
+ - input
+ - text-area
+relatedProps:
+ - width
+status: published
+---
+
+
+
+
+
+
+
+
+
+
+
+
+**Known input length:** Use fixed-width inputs for content with a specific length, such as postal code (7 characters) or year (4 characters).
+
+**Unknown input length:** If you don't know how many characters the user will need (like their name), make your text input 100% of the container.
diff --git a/docs/src/content/guidance/linearprogress-accessibility.mdx b/docs/src/content/guidance/linearprogress-accessibility.mdx
new file mode 100644
index 0000000000..6bb4b8e0ba
--- /dev/null
+++ b/docs/src/content/guidance/linearprogress-accessibility.mdx
@@ -0,0 +1,21 @@
+---
+id: linearprogress-accessibility
+type: do
+description: Provide accessible labels for LinearProgress
+topic: screen-readers
+tags:
+ - linear-progress
+ - accessibility
+ - progress
+appliesTo:
+ components:
+ - linear-progress
+relatedProps:
+ - ariaLabel
+ - ariaLabelledBy
+status: published
+---
+
+
+
+
diff --git a/docs/src/content/guidance/modal-concise-title.mdx b/docs/src/content/guidance/modal-concise-title.mdx
new file mode 100644
index 0000000000..e8f426bc3e
--- /dev/null
+++ b/docs/src/content/guidance/modal-concise-title.mdx
@@ -0,0 +1,23 @@
+---
+id: modal-concise-title
+type: do
+description: Use a concise and descriptive modal title that spans less than one line.
+topic: content
+tags:
+ - modal
+ - headings
+appliesTo:
+ components:
+ - modal
+status: published
+---
+
+
+
+ Submitting the assessment will inform the proponent and email a copy of the report.
+
+ Cancel
+ Submit
+
+
+
diff --git a/docs/src/content/guidance/modal-descriptive-destructive-language.mdx b/docs/src/content/guidance/modal-descriptive-destructive-language.mdx
new file mode 100644
index 0000000000..a7c3990fa2
--- /dev/null
+++ b/docs/src/content/guidance/modal-descriptive-destructive-language.mdx
@@ -0,0 +1,24 @@
+---
+id: modal-descriptive-destructive-language
+type: do
+description: Use descriptive language in content and button text for destructive actions.
+topic: content
+tags:
+ - modal
+ - buttons
+ - destructive
+appliesTo:
+ components:
+ - modal
+status: published
+---
+
+
+
+ Are you sure that you want to cancel your application? This action will permanently cancel your application and delete any information collected.
+
+ Back
+ Cancel application
+
+
+
diff --git a/docs/src/content/guidance/modal-destructive-final-action.mdx b/docs/src/content/guidance/modal-destructive-final-action.mdx
new file mode 100644
index 0000000000..f230320ec6
--- /dev/null
+++ b/docs/src/content/guidance/modal-destructive-final-action.mdx
@@ -0,0 +1,24 @@
+---
+id: modal-destructive-final-action
+type: do
+description: Use a destructive button to indicate the final destructive action.
+topic: interaction
+tags:
+ - modal
+ - buttons
+ - destructive
+appliesTo:
+ components:
+ - modal
+status: published
+---
+
+
+
+ Are you sure that you want to delete this record?
+
+ Cancel
+ Delete record
+
+
+
diff --git a/docs/src/content/guidance/modal-dont-actions-and-close.mdx b/docs/src/content/guidance/modal-dont-actions-and-close.mdx
new file mode 100644
index 0000000000..480ae45226
--- /dev/null
+++ b/docs/src/content/guidance/modal-dont-actions-and-close.mdx
@@ -0,0 +1,23 @@
+---
+id: modal-dont-actions-and-close
+type: dont
+description: Don't provide both action buttons and a close button on the same modal.
+topic: interaction
+tags:
+ - modal
+ - buttons
+appliesTo:
+ components:
+ - modal
+status: published
+---
+
+
+
+ Submitting the assessment will inform the proponent.
+
+ Secondary
+ Primary
+
+
+
diff --git a/docs/src/content/guidance/multiactionbutton-descriptive-label.mdx b/docs/src/content/guidance/multiactionbutton-descriptive-label.mdx
new file mode 100644
index 0000000000..492dd80305
--- /dev/null
+++ b/docs/src/content/guidance/multiactionbutton-descriptive-label.mdx
@@ -0,0 +1,22 @@
+---
+id: multiactionbutton-descriptive-label
+type: do
+description: Label multi action buttons to describe the category of actions, not vague labels like "More".
+topic: content
+tags:
+ - multi-action-button
+ - labels
+appliesTo:
+ components:
+ - multi-action-button
+status: published
+---
+
+
+
+ Actions
+
Delete
+
Schedule for later
+
Move to Draft
+
+
diff --git a/docs/src/content/guidance/multiactionbutton-dont-exceed-six-items.mdx b/docs/src/content/guidance/multiactionbutton-dont-exceed-six-items.mdx
new file mode 100644
index 0000000000..3162f28786
--- /dev/null
+++ b/docs/src/content/guidance/multiactionbutton-dont-exceed-six-items.mdx
@@ -0,0 +1,26 @@
+---
+id: multiactionbutton-dont-exceed-six-items
+type: dont
+description: Don't exceed six menu items in a multi action button.
+topic: usage
+tags:
+ - multi-action-button
+ - limits
+appliesTo:
+ components:
+ - multi-action-button
+status: published
+---
+
+
+
+ Actions
+
Enter result
+
Exit and Save
+
Exit without Save
+
Save to Draft
+
Exit and Export
+
Delete
+
Exit
+
+
diff --git a/docs/src/content/guidance/multiactionbutton-important-items-first.mdx b/docs/src/content/guidance/multiactionbutton-important-items-first.mdx
new file mode 100644
index 0000000000..1fba035247
--- /dev/null
+++ b/docs/src/content/guidance/multiactionbutton-important-items-first.mdx
@@ -0,0 +1,22 @@
+---
+id: multiactionbutton-important-items-first
+type: do
+description: Place the most important or commonly used items at the top of the options list.
+topic: content
+tags:
+ - multi-action-button
+ - ordering
+appliesTo:
+ components:
+ - multi-action-button
+status: published
+---
+
+
+
+ Actions
+
Delete
+
Schedule for later
+
Save to Draft
+
+
diff --git a/docs/src/content/guidance/no-essential-info-in-tooltips.mdx b/docs/src/content/guidance/no-essential-info-in-tooltips.mdx
new file mode 100644
index 0000000000..da7e2aadc3
--- /dev/null
+++ b/docs/src/content/guidance/no-essential-info-in-tooltips.mdx
@@ -0,0 +1,25 @@
+---
+id: no-essential-info-in-tooltips
+type: dont
+description: Don't use tooltips to communicate essential information such as required field indicators, error messages, critical instructions, or information needed to complete a task.
+topic: other
+tags:
+ - tooltip
+ - accessibility
+ - usability
+appliesTo:
+ components:
+ - tooltip
+status: published
+---
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/notification-above-fixed.mdx b/docs/src/content/guidance/notification-above-fixed.mdx
new file mode 100644
index 0000000000..fea508893b
--- /dev/null
+++ b/docs/src/content/guidance/notification-above-fixed.mdx
@@ -0,0 +1,28 @@
+---
+id: notification-above-fixed
+type: do
+description: Place your temporary notification above existing fixed position elements.
+topic: feedback
+tags:
+ - notification
+ - temporary-notification
+ - positioning
+ - layout
+appliesTo:
+ components:
+ - notification
+status: published
+---
+
+
+
+
+
+ Your profile information has been updated.
+
+
+
+ Click to chat
+
+
+
diff --git a/docs/src/content/guidance/notification-action-feedback.mdx b/docs/src/content/guidance/notification-action-feedback.mdx
new file mode 100644
index 0000000000..429194f96c
--- /dev/null
+++ b/docs/src/content/guidance/notification-action-feedback.mdx
@@ -0,0 +1,20 @@
+---
+id: notification-action-feedback
+type: do
+description: Use a temporary notification to communicate actions that have just taken place to the user.
+topic: feedback
+tags:
+ - notification
+ - temporary-notification
+ - feedback
+appliesTo:
+ components:
+ - notification
+status: published
+---
+
+
+
+ Nachos have been added to your cart.
+
+
diff --git a/docs/src/content/guidance/notification-buttons.mdx b/docs/src/content/guidance/notification-buttons.mdx
new file mode 100644
index 0000000000..abe10fbc69
--- /dev/null
+++ b/docs/src/content/guidance/notification-buttons.mdx
@@ -0,0 +1,21 @@
+---
+id: notification-buttons
+type: dont
+description: Never put critical actions or buttons inside a temporary notification as they will disappear automatically.
+topic: feedback
+tags:
+ - notification
+ - temporary-notification
+ - actions
+ - accessibility
+appliesTo:
+ components:
+ - notification
+status: published
+---
+
+
+
+ Message received. Submit
+
+
diff --git a/docs/src/content/guidance/notification-concise.mdx b/docs/src/content/guidance/notification-concise.mdx
new file mode 100644
index 0000000000..36713840c2
--- /dev/null
+++ b/docs/src/content/guidance/notification-concise.mdx
@@ -0,0 +1,20 @@
+---
+id: notification-concise
+type: do
+description: Keep content short and concise.
+topic: feedback
+tags:
+ - notification
+ - temporary-notification
+ - content
+appliesTo:
+ components:
+ - notification
+status: published
+---
+
+
+
+ Your profile was created.
+
+
diff --git a/docs/src/content/guidance/notification-critical-actions.mdx b/docs/src/content/guidance/notification-critical-actions.mdx
new file mode 100644
index 0000000000..d9ef8fbcfa
--- /dev/null
+++ b/docs/src/content/guidance/notification-critical-actions.mdx
@@ -0,0 +1,21 @@
+---
+id: notification-critical-actions
+type: dont
+description: Don't put critical actions for the user in a temporary notification as they automatically dismiss.
+topic: feedback
+tags:
+ - notification
+ - temporary-notification
+ - actions
+ - accessibility
+appliesTo:
+ components:
+ - notification
+status: published
+---
+
+
+
+ Submit your application Submit
+
+
diff --git a/docs/src/content/guidance/notification-loading-ellipsis.mdx b/docs/src/content/guidance/notification-loading-ellipsis.mdx
new file mode 100644
index 0000000000..010265dcee
--- /dev/null
+++ b/docs/src/content/guidance/notification-loading-ellipsis.mdx
@@ -0,0 +1,21 @@
+---
+id: notification-loading-ellipsis
+type: do
+description: End loading messages with an ellipsis to indicate that the action is ongoing.
+topic: feedback
+tags:
+ - notification
+ - temporary-notification
+ - loading
+ - content
+appliesTo:
+ components:
+ - notification
+status: published
+---
+
+
+
+ Your application is being submitted...
+
+
diff --git a/docs/src/content/guidance/notification-multiple.mdx b/docs/src/content/guidance/notification-multiple.mdx
new file mode 100644
index 0000000000..2d939a8013
--- /dev/null
+++ b/docs/src/content/guidance/notification-multiple.mdx
@@ -0,0 +1,25 @@
+---
+id: notification-multiple
+type: dont
+description: Don't show multiple temporary notifications at the same time as it can overwhelm users before they time out.
+topic: feedback
+tags:
+ - notification
+ - temporary-notification
+ - timing
+appliesTo:
+ components:
+ - notification
+status: published
+---
+
+
+
+
+ Your profile information has been updated.
+
+
+ Your contact information has been updated.
+
+
+
diff --git a/docs/src/content/guidance/notification-one-at-time.mdx b/docs/src/content/guidance/notification-one-at-time.mdx
new file mode 100644
index 0000000000..1461e8fde3
--- /dev/null
+++ b/docs/src/content/guidance/notification-one-at-time.mdx
@@ -0,0 +1,20 @@
+---
+id: notification-one-at-time
+type: do
+description: Only show one temporary notification at a time; subsequent ones appear after initial instances disappear.
+topic: feedback
+tags:
+ - notification
+ - temporary-notification
+ - timing
+appliesTo:
+ components:
+ - notification
+status: published
+---
+
+
+
+ Your profile information has been updated.
+
+
diff --git a/docs/src/content/guidance/notification-reference-info.mdx b/docs/src/content/guidance/notification-reference-info.mdx
new file mode 100644
index 0000000000..0da6209bc0
--- /dev/null
+++ b/docs/src/content/guidance/notification-reference-info.mdx
@@ -0,0 +1,20 @@
+---
+id: notification-reference-info
+type: dont
+description: Don't use a temporary notification for success states where important information is displayed for a user to reference since it will disappear.
+topic: feedback
+tags:
+ - notification
+ - temporary-notification
+ - success
+appliesTo:
+ components:
+ - notification
+status: published
+---
+
+
+
+ Your reference number is 123456.
+
+
diff --git a/docs/src/content/guidance/notificationbanner-dont-middle-of-page.mdx b/docs/src/content/guidance/notificationbanner-dont-middle-of-page.mdx
new file mode 100644
index 0000000000..1f679deaf1
--- /dev/null
+++ b/docs/src/content/guidance/notificationbanner-dont-middle-of-page.mdx
@@ -0,0 +1,23 @@
+---
+id: notificationbanner-dont-middle-of-page
+type: dont
+description: Don't place notification banners in the middle of a page.
+topic: positioning
+tags:
+ - notification-banner
+ - layout
+appliesTo:
+ components:
+ - notification-banner
+status: published
+---
+
+
+
+
Page content above...
+
+ System outage notification
+
+
Page content below...
+
+
diff --git a/docs/src/content/guidance/notificationbanner-dont-multiple-links.mdx b/docs/src/content/guidance/notificationbanner-dont-multiple-links.mdx
new file mode 100644
index 0000000000..29608cf01d
--- /dev/null
+++ b/docs/src/content/guidance/notificationbanner-dont-multiple-links.mdx
@@ -0,0 +1,19 @@
+---
+id: notificationbanner-dont-multiple-links
+type: dont
+description: Don't include more than one link in a notification banner.
+topic: content
+tags:
+ - notification-banner
+ - links
+appliesTo:
+ components:
+ - notification-banner
+status: published
+---
+
+
+
+ First link and a Second link
+
+
diff --git a/docs/src/content/guidance/notificationbanner-full-width-top.mdx b/docs/src/content/guidance/notificationbanner-full-width-top.mdx
new file mode 100644
index 0000000000..d025e65e1d
--- /dev/null
+++ b/docs/src/content/guidance/notificationbanner-full-width-top.mdx
@@ -0,0 +1,19 @@
+---
+id: notificationbanner-full-width-top
+type: do
+description: Place notification banners at full width at the top of the page, right after the header.
+topic: positioning
+tags:
+ - notification-banner
+ - layout
+appliesTo:
+ components:
+ - notification-banner
+status: published
+---
+
+
+
+ Please note the application deadline has been extended by 3 months.
+
+
diff --git a/docs/src/content/guidance/page-requires-one-column-layout.mdx b/docs/src/content/guidance/page-requires-one-column-layout.mdx
new file mode 100644
index 0000000000..903afc9b47
--- /dev/null
+++ b/docs/src/content/guidance/page-requires-one-column-layout.mdx
@@ -0,0 +1,24 @@
+---
+id: page-requires-one-column-layout
+type: do
+description: Use the one column layout to ensure consistent page structure, proper header/footer placement, and responsive behavior.
+topic: other
+tags:
+ - layout
+ - page-structure
+appliesTo:
+ components:
+ - one-column-layout
+status: published
+---
+
+
+
+
+
+
+
+
Main content goes here
+
+
+
diff --git a/docs/src/content/guidance/pagination-disable-at-bounds.mdx b/docs/src/content/guidance/pagination-disable-at-bounds.mdx
new file mode 100644
index 0000000000..f3cd7c0d79
--- /dev/null
+++ b/docs/src/content/guidance/pagination-disable-at-bounds.mdx
@@ -0,0 +1,17 @@
+---
+id: pagination-disable-at-bounds
+type: do
+description: Disable the Previous button on the first page, and the Next button on the last page.
+topic: interaction
+tags:
+ - pagination
+ - buttons
+appliesTo:
+ components:
+ - pagination
+status: published
+---
+
+
+
+
diff --git a/docs/src/content/guidance/pagination-full-width.mdx b/docs/src/content/guidance/pagination-full-width.mdx
new file mode 100644
index 0000000000..7bf0491961
--- /dev/null
+++ b/docs/src/content/guidance/pagination-full-width.mdx
@@ -0,0 +1,17 @@
+---
+id: pagination-full-width
+type: do
+description: Ensure the pagination component is the full width of the table or content it's connected to.
+topic: layout
+tags:
+ - pagination
+ - layout
+appliesTo:
+ components:
+ - pagination
+status: published
+---
+
+
+
+
diff --git a/docs/src/content/guidance/progress-no-full-sentence.mdx b/docs/src/content/guidance/progress-no-full-sentence.mdx
new file mode 100644
index 0000000000..cdaa714299
--- /dev/null
+++ b/docs/src/content/guidance/progress-no-full-sentence.mdx
@@ -0,0 +1,18 @@
+---
+id: progress-no-full-sentence
+type: dont
+description: Don't place a full sentence in the indicator's label.
+topic: content
+tags:
+ - progress-indicator
+ - content
+ - loading
+appliesTo:
+ components:
+ - circular-progress
+status: published
+---
+
+
+
+
diff --git a/docs/src/content/guidance/progress-short-message.mdx b/docs/src/content/guidance/progress-short-message.mdx
new file mode 100644
index 0000000000..d5f05d3027
--- /dev/null
+++ b/docs/src/content/guidance/progress-short-message.mdx
@@ -0,0 +1,18 @@
+---
+id: progress-short-message
+type: do
+description: Keep loading messages short and concise.
+topic: content
+tags:
+ - progress-indicator
+ - content
+ - loading
+appliesTo:
+ components:
+ - circular-progress
+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
new file mode 100644
index 0000000000..1bf8c79dcd
--- /dev/null
+++ b/docs/src/content/guidance/radio-dont-more-than-seven.mdx
@@ -0,0 +1,26 @@
+---
+id: radio-dont-more-than-seven
+type: dont
+description: Don't use radios when there are more than 7 options - use a dropdown instead.
+topic: usage
+tags:
+ - radio
+ - dropdown
+appliesTo:
+ components:
+ - radio
+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
new file mode 100644
index 0000000000..619892161e
--- /dev/null
+++ b/docs/src/content/guidance/radio-dont-nest-revealed-content.mdx
@@ -0,0 +1,26 @@
+---
+id: radio-dont-nest-revealed-content
+type: dont
+description: Don't nest multiple layers of conditionally revealed questions.
+topic: interaction
+tags:
+ - radio
+ - forms
+ - accessibility
+appliesTo:
+ components:
+ - radio
+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
new file mode 100644
index 0000000000..ff8f0ab54a
--- /dev/null
+++ b/docs/src/content/guidance/radio-dont-period-after-label.mdx
@@ -0,0 +1,19 @@
+---
+id: radio-dont-period-after-label
+type: dont
+description: Don't include a period after a radio label.
+topic: content
+tags:
+ - radio
+ - labels
+appliesTo:
+ components:
+ - radio
+status: published
+---
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/radio-dont-preselect.mdx b/docs/src/content/guidance/radio-dont-preselect.mdx
new file mode 100644
index 0000000000..76156b23f5
--- /dev/null
+++ b/docs/src/content/guidance/radio-dont-preselect.mdx
@@ -0,0 +1,20 @@
+---
+id: radio-dont-preselect
+type: dont
+description: Don't preselect radio items - users might miss the question or submit the wrong answer.
+topic: interaction
+tags:
+ - radio
+ - defaults
+appliesTo:
+ components:
+ - radio
+status: published
+---
+
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/radio-horizontal-short-options.mdx b/docs/src/content/guidance/radio-horizontal-short-options.mdx
new file mode 100644
index 0000000000..a92f5058b4
--- /dev/null
+++ b/docs/src/content/guidance/radio-horizontal-short-options.mdx
@@ -0,0 +1,20 @@
+---
+id: radio-horizontal-short-options
+type: do
+description: Consider horizontal listing when presenting 2-3 short options like Yes/No.
+topic: layout
+tags:
+ - radio
+ - layout
+appliesTo:
+ components:
+ - radio
+status: published
+---
+
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/table-semantic-structure.mdx b/docs/src/content/guidance/table-semantic-structure.mdx
new file mode 100644
index 0000000000..33629f0930
--- /dev/null
+++ b/docs/src/content/guidance/table-semantic-structure.mdx
@@ -0,0 +1,38 @@
+---
+id: table-semantic-structure
+type: do
+description: Use proper semantic HTML table structure (thead, tbody, tr, th, td) for accessibility.
+topic: screen-readers
+tags:
+ - table
+ - accessibility
+ - semantics
+appliesTo:
+ components:
+ - table
+status: published
+---
+
+
+
+
+
+
Name
+
Date
+
Status
+
+
+
+
+
John Smith
+
Jan 15, 2024
+
Active
+
+
+
Jane Doe
+
Feb 20, 2024
+
Pending
+
+
+
+
diff --git a/docs/src/content/guidance/tabs-dont-indicate-progress.mdx b/docs/src/content/guidance/tabs-dont-indicate-progress.mdx
new file mode 100644
index 0000000000..6e678d47cc
--- /dev/null
+++ b/docs/src/content/guidance/tabs-dont-indicate-progress.mdx
@@ -0,0 +1,20 @@
+---
+id: tabs-dont-indicate-progress
+type: dont
+description: Don't use tabs to indicate progress.
+topic: usage
+tags:
+ - tabs
+appliesTo:
+ components:
+ - tabs
+status: published
+---
+
+
+
+ Step 1 content
+ Step 2 content
+ Step 3 content
+
+
diff --git a/docs/src/content/guidance/tabs-dont-need-multiple-visible.mdx b/docs/src/content/guidance/tabs-dont-need-multiple-visible.mdx
new file mode 100644
index 0000000000..6f851d3411
--- /dev/null
+++ b/docs/src/content/guidance/tabs-dont-need-multiple-visible.mdx
@@ -0,0 +1,19 @@
+---
+id: tabs-dont-need-multiple-visible
+type: dont
+description: Don't use tabs if users need to see content from multiple tabs simultaneously.
+topic: usage
+tags:
+ - tabs
+appliesTo:
+ components:
+ - tabs
+status: published
+---
+
+
+
+ Data the user needs to compare...
+ ...with data in another tab
+
+
diff --git a/docs/src/content/guidance/tabs-dont-nest.mdx b/docs/src/content/guidance/tabs-dont-nest.mdx
new file mode 100644
index 0000000000..7360965f10
--- /dev/null
+++ b/docs/src/content/guidance/tabs-dont-nest.mdx
@@ -0,0 +1,25 @@
+---
+id: tabs-dont-nest
+type: dont
+description: Avoid nesting tabs inside other tabs.
+topic: usage
+tags:
+ - tabs
+ - layout
+appliesTo:
+ components:
+ - tabs
+status: published
+---
+
+
+
+
+
+ Nested content
+ Nested content
+
+
+ Content
+
+
diff --git a/docs/src/content/guidance/tabs-dont-truncate-labels.mdx b/docs/src/content/guidance/tabs-dont-truncate-labels.mdx
new file mode 100644
index 0000000000..c7758ddae4
--- /dev/null
+++ b/docs/src/content/guidance/tabs-dont-truncate-labels.mdx
@@ -0,0 +1,21 @@
+---
+id: tabs-dont-truncate-labels
+type: dont
+description: Don't truncate tab labels - use short labels instead.
+topic: content
+tags:
+ - tabs
+ - labels
+appliesTo:
+ components:
+ - tabs
+status: published
+---
+
+
+
+ Content
+ Content
+ Content
+
+
diff --git a/docs/src/content/guidance/tabs-preselect-on-load.mdx b/docs/src/content/guidance/tabs-preselect-on-load.mdx
new file mode 100644
index 0000000000..00cf8f8b74
--- /dev/null
+++ b/docs/src/content/guidance/tabs-preselect-on-load.mdx
@@ -0,0 +1,21 @@
+---
+id: tabs-preselect-on-load
+type: do
+description: Always have one of the tabs pre-selected on page load.
+topic: interaction
+tags:
+ - tabs
+ - defaults
+appliesTo:
+ components:
+ - tabs
+status: published
+---
+
+
+
+ Open content
+ Completed content
+ Archived content
+
+
diff --git a/docs/src/content/guidance/textarea-char-count-predictable.mdx b/docs/src/content/guidance/textarea-char-count-predictable.mdx
new file mode 100644
index 0000000000..5bb92c6622
--- /dev/null
+++ b/docs/src/content/guidance/textarea-char-count-predictable.mdx
@@ -0,0 +1,20 @@
+---
+id: textarea-char-count-predictable
+type: dont
+description: Don't use the character counter for input fields where user entries typically have standard or predictable lengths.
+topic: forms
+tags:
+ - textarea
+ - character-count
+appliesTo:
+ components:
+ - textarea
+ - form-item
+status: published
+---
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/textarea-char-count-valid-reason.mdx b/docs/src/content/guidance/textarea-char-count-valid-reason.mdx
new file mode 100644
index 0000000000..c125d0460d
--- /dev/null
+++ b/docs/src/content/guidance/textarea-char-count-valid-reason.mdx
@@ -0,0 +1,21 @@
+---
+id: textarea-char-count-valid-reason
+type: do
+description: Use the character count only when there's a valid reason to limit the number of characters.
+topic: forms
+tags:
+ - textarea
+ - character-count
+ - validation
+appliesTo:
+ components:
+ - textarea
+ - form-item
+status: published
+---
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/textarea-height-match-content.mdx b/docs/src/content/guidance/textarea-height-match-content.mdx
new file mode 100644
index 0000000000..e2c93dff56
--- /dev/null
+++ b/docs/src/content/guidance/textarea-height-match-content.mdx
@@ -0,0 +1,20 @@
+---
+id: textarea-height-match-content
+type: do
+description: Make empty text areas as tall as the content they are expected to contain.
+topic: forms
+tags:
+ - textarea
+ - sizing
+appliesTo:
+ components:
+ - textarea
+ - form-item
+status: published
+---
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/textarea-max-width.mdx b/docs/src/content/guidance/textarea-max-width.mdx
new file mode 100644
index 0000000000..e31b141954
--- /dev/null
+++ b/docs/src/content/guidance/textarea-max-width.mdx
@@ -0,0 +1,21 @@
+---
+id: textarea-max-width
+type: do
+description: Ensure that the text area width is no longer than 75 characters per line; ideal line length is 45-75 characters.
+topic: forms
+tags:
+ - textarea
+ - sizing
+ - readability
+appliesTo:
+ components:
+ - textarea
+ - form-item
+status: published
+---
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/textarea-one-line.mdx b/docs/src/content/guidance/textarea-one-line.mdx
new file mode 100644
index 0000000000..800e2447a4
--- /dev/null
+++ b/docs/src/content/guidance/textarea-one-line.mdx
@@ -0,0 +1,22 @@
+---
+id: textarea-one-line
+type: dont
+description: Don't use a text area which is only one line high; instead, use text input if just one line is needed.
+topic: forms
+tags:
+ - textarea
+ - input
+ - sizing
+appliesTo:
+ components:
+ - textarea
+ - input
+ - form-item
+status: published
+---
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/textarea-vs-input.mdx b/docs/src/content/guidance/textarea-vs-input.mdx
new file mode 100644
index 0000000000..0fcb8f80d4
--- /dev/null
+++ b/docs/src/content/guidance/textarea-vs-input.mdx
@@ -0,0 +1,21 @@
+---
+id: textarea-vs-input
+type: do
+description: Use a text area to input content longer than a single line, such as descriptions, comments, or feedback.
+topic: types
+tags:
+ - textarea
+ - input
+ - forms
+appliesTo:
+ components:
+ - text-area
+ - input
+status: published
+---
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/textarea-word-count-suggestion.mdx b/docs/src/content/guidance/textarea-word-count-suggestion.mdx
new file mode 100644
index 0000000000..a0f0ffc8d4
--- /dev/null
+++ b/docs/src/content/guidance/textarea-word-count-suggestion.mdx
@@ -0,0 +1,21 @@
+---
+id: textarea-word-count-suggestion
+type: do
+description: If you suggest a specific length for an answer to a question, display a word count to help guide the user.
+topic: forms
+tags:
+ - textarea
+ - word-count
+ - content
+appliesTo:
+ components:
+ - textarea
+ - form-item
+status: published
+---
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/tooltip-describe-icon-button.mdx b/docs/src/content/guidance/tooltip-describe-icon-button.mdx
new file mode 100644
index 0000000000..082b78c67a
--- /dev/null
+++ b/docs/src/content/guidance/tooltip-describe-icon-button.mdx
@@ -0,0 +1,21 @@
+---
+id: tooltip-describe-icon-button
+type: do
+description: Use tooltips to describe an icon button and provide clarity on what the icon button will do.
+topic: feedback
+tags:
+ - tooltip
+ - icon-button
+ - accessibility
+appliesTo:
+ components:
+ - tooltip
+ - icon-button
+status: published
+---
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/tooltip-force-scroll.mdx b/docs/src/content/guidance/tooltip-force-scroll.mdx
new file mode 100644
index 0000000000..bcd2b9136b
--- /dev/null
+++ b/docs/src/content/guidance/tooltip-force-scroll.mdx
@@ -0,0 +1,27 @@
+---
+id: tooltip-force-scroll
+type: dont
+description: Don't position a tooltip in a way that forces the user to scroll to view the tooltip content.
+topic: feedback
+tags:
+ - tooltip
+ - positioning
+ - usability
+appliesTo:
+ components:
+ - tooltip
+status: published
+---
+
+
+
+
+
+
+
+
+
+ We will send important updates to this email address.
+
+
+
diff --git a/docs/src/content/guidance/tooltip-inconsistent-icon-buttons.mdx b/docs/src/content/guidance/tooltip-inconsistent-icon-buttons.mdx
new file mode 100644
index 0000000000..e034c365f3
--- /dev/null
+++ b/docs/src/content/guidance/tooltip-inconsistent-icon-buttons.mdx
@@ -0,0 +1,25 @@
+---
+id: tooltip-inconsistent-icon-buttons
+type: dont
+description: Don't use tooltips inconsistently; if one icon button has a tooltip, the rest of the icon buttons must also have tooltips.
+topic: feedback
+tags:
+ - tooltip
+ - icon-button
+ - consistency
+appliesTo:
+ components:
+ - tooltip
+ - icon-button
+status: published
+---
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/tooltip-over-140-chars.mdx b/docs/src/content/guidance/tooltip-over-140-chars.mdx
new file mode 100644
index 0000000000..6886d8efb5
--- /dev/null
+++ b/docs/src/content/guidance/tooltip-over-140-chars.mdx
@@ -0,0 +1,24 @@
+---
+id: tooltip-over-140-chars
+type: dont
+description: Don't add more than 140 characters to a tooltip; for lengthy information use the details component.
+topic: feedback
+tags:
+ - tooltip
+ - content
+ - details
+appliesTo:
+ components:
+ - tooltip
+ - details
+status: published
+---
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/tooltip-too-far.mdx b/docs/src/content/guidance/tooltip-too-far.mdx
new file mode 100644
index 0000000000..56f9dd2925
--- /dev/null
+++ b/docs/src/content/guidance/tooltip-too-far.mdx
@@ -0,0 +1,23 @@
+---
+id: tooltip-too-far
+type: dont
+description: Don't position a tooltip too far from the element.
+topic: feedback
+tags:
+ - tooltip
+ - positioning
+ - usability
+appliesTo:
+ components:
+ - tooltip
+status: published
+---
+
+
+
+
+
+ Tooltip
+
+
+
diff --git a/docs/src/content/guidance/tooltip-vital-info.mdx b/docs/src/content/guidance/tooltip-vital-info.mdx
new file mode 100644
index 0000000000..00d0b58e07
--- /dev/null
+++ b/docs/src/content/guidance/tooltip-vital-info.mdx
@@ -0,0 +1,23 @@
+---
+id: tooltip-vital-info
+type: dont
+description: Don't use tooltips for information that is vital to task completion.
+topic: feedback
+tags:
+ - tooltip
+ - accessibility
+ - content
+appliesTo:
+ components:
+ - tooltip
+status: published
+---
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/content/guidance/tooltip-when-to-use.mdx b/docs/src/content/guidance/tooltip-when-to-use.mdx
new file mode 100644
index 0000000000..de847a865f
--- /dev/null
+++ b/docs/src/content/guidance/tooltip-when-to-use.mdx
@@ -0,0 +1,20 @@
+---
+id: tooltip-when-to-use
+type: do
+description: Use tooltips for additional context that enhances understanding, definitions of terms, or keyboard shortcuts.
+topic: other
+tags:
+ - tooltip
+ - accessibility
+ - usability
+appliesTo:
+ components:
+ - tooltip
+status: published
+---
+
+
+
+ Save
+
+
diff --git a/docs/src/data/configurations/accordion.ts b/docs/src/data/configurations/accordion.ts
new file mode 100644
index 0000000000..02e4325c8d
--- /dev/null
+++ b/docs/src/data/configurations/accordion.ts
@@ -0,0 +1,151 @@
+/**
+ * Accordion Component Configurations
+ *
+ * Accordions show and hide content sections.
+ */
+
+import type { ComponentConfigurations } from './types';
+
+export const accordionConfigurations: ComponentConfigurations = {
+ componentSlug: 'accordion',
+ componentName: 'Accordion',
+ defaultConfigurationId: 'basic',
+
+ configurations: [
+ {
+ id: 'basic',
+ name: 'Basic accordion',
+ description: 'Single accordion with heading',
+ code: {
+ react: `
+ You will need to provide proof of identity, proof of address,
+ and any relevant supporting documentation.
+`,
+ angular: `
+ You will need to provide proof of identity, proof of address,
+ and any relevant supporting documentation.
+`,
+ webComponents: `
+ You will need to provide proof of identity, proof of address,
+ and any relevant supporting documentation.
+`,
+ },
+ },
+ {
+ id: 'open',
+ name: 'Open by default',
+ description: 'Accordion that starts expanded',
+ code: {
+ react: `
+ This content is visible by default when the page loads.
+`,
+ angular: `
+ This content is visible by default when the page loads.
+`,
+ webComponents: `
+ This content is visible by default when the page loads.
+`,
+ },
+ },
+ {
+ id: 'with-secondary-text',
+ name: 'With secondary text',
+ description: 'Accordion with additional context in header',
+ code: {
+ react: `
+ Review the latest requirements before submitting your application.
+`,
+ angular: `
+ Review the latest requirements before submitting your application.
+`,
+ webComponents: `
+ Review the latest requirements before submitting your application.
+`,
+ },
+ },
+ {
+ id: 'heading-sizes',
+ name: 'Heading sizes',
+ description: 'Small and medium heading sizes',
+ code: {
+ react: `
+ Content with small heading.
+
+
+ Content with medium heading.
+`,
+ angular: `
+ Content with small heading.
+
+
+ Content with medium heading.
+`,
+ webComponents: `
+ Content with small heading.
+
+
+ Content with medium heading.
+`,
+ },
+ },
+ {
+ id: 'icon-position',
+ name: 'Icon position',
+ description: 'Toggle icon on left or right',
+ code: {
+ react: `
+ The expand/collapse icon is on the left.
+
+
+ The expand/collapse icon is on the right.
+`,
+ angular: `
+ The expand/collapse icon is on the left.
+
+
+ The expand/collapse icon is on the right.
+`,
+ webComponents: `
+ The expand/collapse icon is on the left.
+
+
+ The expand/collapse icon is on the right.
+`,
+ },
+ },
+ {
+ id: 'multiple',
+ name: 'Multiple accordions',
+ description: 'FAQ-style accordion group',
+ code: {
+ react: `
+ Submit your application online through our portal.
+
+
+ You must be an Alberta resident and meet the program criteria.
+
+
+ Applications are typically processed within 10 business days.
+`,
+ angular: `
+ Submit your application online through our portal.
+
+
+ You must be an Alberta resident and meet the program criteria.
+
+
+ Applications are typically processed within 10 business days.
+`,
+ webComponents: `
+ Submit your application online through our portal.
+
+
+ You must be an Alberta resident and meet the program criteria.
+
+
+ Applications are typically processed within 10 business days.
+`,
+ },
+ },
+ ],
+};
diff --git a/docs/src/data/configurations/app-header-menu.ts b/docs/src/data/configurations/app-header-menu.ts
new file mode 100644
index 0000000000..41ebec2456
--- /dev/null
+++ b/docs/src/data/configurations/app-header-menu.ts
@@ -0,0 +1,44 @@
+/**
+ * AppHeaderMenu Component Configurations
+ *
+ * AppHeaderMenu is a child component of AppHeader.
+ */
+
+import type { ComponentConfigurations } from './types';
+
+export const appHeaderMenuConfigurations: ComponentConfigurations = {
+ componentSlug: 'app-header-menu',
+ componentName: 'App header menu',
+ defaultConfigurationId: 'basic',
+
+ configurations: [
+ {
+ id: 'basic',
+ name: 'Basic app header menu',
+ description: 'Navigation menu within AppHeader',
+ code: {
+ react: `
+
+ Dashboard
+ Reports
+ Settings
+
+`,
+ angular: `
+
+ Dashboard
+ Reports
+ Settings
+
+`,
+ webComponents: `
+
+ Dashboard
+ Reports
+ Settings
+
+`,
+ },
+ },
+ ],
+};
diff --git a/docs/src/data/configurations/app-header.ts b/docs/src/data/configurations/app-header.ts
new file mode 100644
index 0000000000..e973e0c9e0
--- /dev/null
+++ b/docs/src/data/configurations/app-header.ts
@@ -0,0 +1,98 @@
+/**
+ * AppHeader Component Configurations
+ *
+ * App header provides main navigation for applications.
+ */
+
+import type { ComponentConfigurations } from './types';
+
+export const appHeaderConfigurations: ComponentConfigurations = {
+ componentSlug: 'app-header',
+ componentName: 'App header',
+ defaultConfigurationId: 'basic',
+
+ configurations: [
+ {
+ id: 'basic',
+ name: 'Basic app header',
+ description: 'Simple application header',
+ code: {
+ react: ``,
+ angular: ``,
+ webComponents: ``,
+ },
+ },
+ {
+ id: 'with-url',
+ name: 'With home link',
+ description: 'Header with clickable title',
+ code: {
+ react: ``,
+ angular: ``,
+ webComponents: ``,
+ },
+ },
+ {
+ id: 'with-actions',
+ name: 'With actions',
+ description: 'Header with action buttons',
+ code: {
+ react: `
+
+
+
+
diff --git a/docs/src/lib/content-queries.ts b/docs/src/lib/content-queries.ts
new file mode 100644
index 0000000000..76ce2a9ef2
--- /dev/null
+++ b/docs/src/lib/content-queries.ts
@@ -0,0 +1,166 @@
+import { getCollection, type CollectionEntry } from 'astro:content';
+import fs from 'node:fs/promises';
+import path from 'node:path';
+
+// Types for extracted API data
+export interface PropDefinition {
+ name: string;
+ type: string;
+ typeLabel?: string;
+ values?: string[];
+ required: boolean;
+ default: string | null;
+ description: string;
+}
+
+export interface EventDefinition {
+ name: string;
+ type: string;
+ description: string;
+ frameworks: string[];
+}
+
+export interface SlotDefinition {
+ name: string;
+ description: string;
+}
+
+export interface ComponentApi {
+ componentSlug: string;
+ extractedFrom: string;
+ extractedAt: string;
+ props: PropDefinition[];
+ events: EventDefinition[];
+ slots: SlotDefinition[];
+}
+
+/**
+ * Get extracted API data for a component
+ */
+export async function getComponentApi(slug: string): Promise {
+ try {
+ const apiPath = path.join(process.cwd(), 'generated', 'component-apis', `${slug}.json`);
+ const content = await fs.readFile(apiPath, 'utf-8');
+ return JSON.parse(content) as ComponentApi;
+ } catch (error) {
+ console.warn(`No API data found for component: ${slug}`);
+ return null;
+ }
+}
+
+/**
+ * Get all guidance that applies to a specific component
+ */
+export async function getGuidanceForComponent(
+ componentSlug: string
+): Promise[]> {
+ const allGuidance = await getCollection('guidance');
+
+ return allGuidance.filter(guidance =>
+ guidance.data.appliesTo?.components?.includes(componentSlug)
+ );
+}
+
+/**
+ * Get all examples that use a specific component
+ */
+export async function getExamplesForComponent(
+ componentSlug: string
+): Promise[]> {
+ const allExamples = await getCollection('examples');
+
+ return allExamples.filter(example =>
+ example.data.components.includes(componentSlug)
+ );
+}
+
+/**
+ * Group guidance by topic for page section rendering
+ */
+export function groupGuidanceByTopic(
+ guidance: CollectionEntry<'guidance'>[]
+): Record[]> {
+ const grouped: Record[]> = {};
+
+ for (const item of guidance) {
+ const topic = item.data.topic;
+ if (!grouped[topic]) {
+ grouped[topic] = [];
+ }
+ grouped[topic].push(item);
+ }
+
+ return grouped;
+}
+
+// Topic categories for organizing guidance (must match schema in config.ts)
+export const USAGE_TOPICS = ['types', 'states', 'sizing', 'icons', 'positioning', 'content', 'other'] as const;
+export const ACCESSIBILITY_TOPICS = ['screen-readers', 'keyboard', 'focus'] as const;
+
+/**
+ * Separate guidance into usage and accessibility categories
+ */
+export function categorizeGuidance(guidance: CollectionEntry<'guidance'>[]) {
+ const usageGuidance = guidance.filter(g =>
+ USAGE_TOPICS.includes(g.data.topic as typeof USAGE_TOPICS[number])
+ );
+
+ const accessibilityGuidance = guidance.filter(g =>
+ ACCESSIBILITY_TOPICS.includes(g.data.topic as typeof ACCESSIBILITY_TOPICS[number])
+ );
+
+ return {
+ usage: groupGuidanceByTopic(usageGuidance),
+ accessibility: groupGuidanceByTopic(accessibilityGuidance),
+ };
+}
+
+/**
+ * Get all content with a specific tag
+ */
+export async function getContentByTag(tag: string) {
+ const [components, guidance, examples] = await Promise.all([
+ getCollection('components'),
+ getCollection('guidance'),
+ getCollection('examples'),
+ ]);
+
+ return {
+ components: components.filter(c => c.data.tags?.includes(tag)),
+ guidance: guidance.filter(g => g.data.tags?.includes(tag)),
+ examples: examples.filter(e => e.data.tags?.includes(tag)),
+ };
+}
+
+/**
+ * Get all visible components (excludes hidden)
+ */
+export async function getVisibleComponents(): Promise[]> {
+ const allComponents = await getCollection('components');
+ return allComponents.filter(c => !c.data.hidden);
+}
+
+/**
+ * Get related components from a component entry (excludes hidden)
+ */
+export async function getRelatedComponents(
+ relatedSlugs: string[]
+): Promise[]> {
+ const allComponents = await getCollection('components');
+
+ return allComponents.filter(c => {
+ if (c.data.hidden) return false;
+ const slug = c.data.slug || c.slug;
+ return relatedSlugs.includes(slug);
+ });
+}
+
+/**
+ * Format topic name for display
+ */
+export function formatTopicName(topic: string): string {
+ return topic
+ .split('-')
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
+ .join(' ');
+}
diff --git a/docs/src/lib/example-code.ts b/docs/src/lib/example-code.ts
new file mode 100644
index 0000000000..6747d18b6e
--- /dev/null
+++ b/docs/src/lib/example-code.ts
@@ -0,0 +1,62 @@
+/**
+ * Helper functions to read example code files at build time
+ */
+
+import fs from 'node:fs/promises';
+import path from 'node:path';
+
+export interface ExampleCode {
+ react?: string;
+ angular?: {
+ template: string;
+ component?: string;
+ };
+ webComponents?: string;
+}
+
+/**
+ * Read all code files for an example
+ * @param exampleSlug - The example folder name (e.g., "button-with-icon")
+ * @returns Object with code for each framework
+ */
+export async function getExampleCode(exampleSlug: string): Promise {
+ const exampleDir = path.join(process.cwd(), 'src/content/examples', exampleSlug);
+ const code: ExampleCode = {};
+
+ // Read React code
+ try {
+ code.react = await fs.readFile(path.join(exampleDir, 'react.tsx'), 'utf-8');
+ } catch {
+ // File doesn't exist
+ }
+
+ // Read Angular code (template + component)
+ try {
+ const template = await fs.readFile(path.join(exampleDir, 'angular.html'), 'utf-8');
+ let component: string | undefined;
+ try {
+ component = await fs.readFile(path.join(exampleDir, 'angular.ts'), 'utf-8');
+ } catch {
+ // Component file is optional
+ }
+ code.angular = { template, component };
+ } catch {
+ // Files don't exist
+ }
+
+ // Read Web Components code
+ try {
+ code.webComponents = await fs.readFile(path.join(exampleDir, 'web-components.html'), 'utf-8');
+ } catch {
+ // File doesn't exist
+ }
+
+ return code;
+}
+
+/**
+ * Add version="2" attribute to all goa- elements for v2 styling
+ */
+export function addVersionAttribute(html: string): string {
+ return html.replace(/{`...`} blocks */
+ css?: string;
+ /** Setup code: const declarations with JSX, useState hooks */
+ setup?: string;
+ /** Main JSX body (cleaned of imports, function wrapper, fragments) */
+ jsx: string;
+}
+
+export interface ExtractedAngularCode {
+ /** CSS from styles: [...] in @Component decorator */
+ css?: string;
+ /** TypeScript class body (properties + methods, no decorator) */
+ typescript?: string;
+ /** HTML template */
+ template: string;
+}
+
+export interface ExtractedWebComponentsCode {
+ /** CSS from blocks
+ const styleMatch = code.match(/
+
diff --git a/docs/src/pages/components/index.astro b/docs/src/pages/components/index.astro
new file mode 100644
index 0000000000..56261ff764
--- /dev/null
+++ b/docs/src/pages/components/index.astro
@@ -0,0 +1,76 @@
+---
+/**
+ * All Components Page
+ *
+ * Shows all components with:
+ * - Search input
+ * - Filter drawer (category, status)
+ * - Table/List/Card view toggle
+ * - Grouping options
+ * - Two-level sorting
+ */
+import { getCollection } from 'astro:content';
+import ComponentPageLayout from '../../layouts/ComponentPageLayout.astro';
+import { ComponentsGrid } from '../../components/ComponentsGrid';
+
+// Get all visible components (filter out hidden)
+const allComponents = await getCollection('components');
+const visibleComponents = allComponents.filter(c => !c.data.hidden);
+
+// Sort by name (default)
+const sortedComponents = visibleComponents.sort((a, b) =>
+ a.data.name.localeCompare(b.data.name)
+);
+
+// Transform to the shape ComponentsGrid expects
+const components = sortedComponents.map(component => ({
+ slug: component.slug,
+ data: component.data,
+}));
+---
+
+
+
+
+
+
All Components
+
+ Reusable parts of the user interface that have been made to support a variety of applications. You can use individual components in many different patterns and contexts.
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/pages/examples/[slug].astro b/docs/src/pages/examples/[slug].astro
new file mode 100644
index 0000000000..a34917067a
--- /dev/null
+++ b/docs/src/pages/examples/[slug].astro
@@ -0,0 +1,232 @@
+---
+/**
+ * Individual Example Page
+ *
+ * Shows a single example with:
+ * - Live preview with framework code tabs
+ * - MDX content (when to use, considerations, etc.)
+ * - Metadata (category, userType, components used)
+ * - Related examples
+ */
+import { getCollection, render } from 'astro:content';
+import ExamplesPageLayout from '../../layouts/ExamplesPageLayout.astro';
+import ExampleDisplay from '../../components/ExampleDisplay.astro';
+
+// Generate static paths for all examples
+export async function getStaticPaths() {
+ const examples = await getCollection('examples');
+ return examples.map((example) => ({
+ params: { slug: example.slug },
+ props: { example },
+ }));
+}
+
+const { example } = Astro.props;
+const { slug } = Astro.params;
+const { data } = example;
+
+// Render the MDX content
+const { Content } = await render(example);
+
+// Get related examples if defined
+let relatedExamples: typeof example[] = [];
+if (data.relatedExamples?.length) {
+ const allExamples = await getCollection('examples');
+ relatedExamples = allExamples.filter(e =>
+ data.relatedExamples?.includes(e.data.id)
+ );
+}
+
+// Format category for display
+function formatCategory(category: string): string {
+ return category
+ .split('-')
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
+ .join(' ');
+}
+
+// Format scale for display
+function formatScale(scale: string): string {
+ return scale.charAt(0).toUpperCase() + scale.slice(1);
+}
+
+// Format user type for display
+function formatUserType(userType: string): string {
+ if (userType === 'both') return 'Citizen & Worker';
+ return userType.charAt(0).toUpperCase() + userType.slice(1);
+}
+
+// Format component name to sentence case (e.g., "form-item" → "Form item")
+function formatComponentName(component: string): string {
+ return component
+ .split('-')
+ .map((word, i) => i === 0 ? word.charAt(0).toUpperCase() + word.slice(1) : word)
+ .join(' ');
+}
+---
+
+
+
+
+
+
+
+ Back to all examples
+
+
+
+
+ Common patterns, pages, tasks, component configurations, flows, and more to use as a starting point when creating government digital services.
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/pages/foundations/index.astro b/docs/src/pages/foundations/index.astro
new file mode 100644
index 0000000000..5837c38e31
--- /dev/null
+++ b/docs/src/pages/foundations/index.astro
@@ -0,0 +1,142 @@
+---
+/**
+ * Foundations - Landing Page
+ *
+ * Placeholder demonstrating the DocumentationPageLayout template.
+ * Content will be migrated from existing documentation in Brief 30.
+ */
+import DocumentationPageLayout from '../../layouts/DocumentationPageLayout.astro';
+---
+
+
+ Foundations
+
+ The foundations of the design system define the core visual language and principles that
+ ensure consistency across all Government of Alberta digital services.
+
+
+
+ This page demonstrates the documentation template. Detailed foundations content will be
+ migrated from the current design system website in a future update.
+
+
+ Our design principles guide every decision we make when building government services.
+ They help teams create experiences that are consistent, accessible, and user-centered.
+
+
+
+
+ Start with user needs: Design services that meet the needs of Albertans,
+ not the needs of government processes.
+
+
+ Be inclusive: Create services that work for everyone, regardless of
+ ability, device, or connectivity.
+
+
+ Keep it simple: Remove complexity and help users accomplish their tasks
+ with minimal effort.
+
+
+ Be consistent: Use familiar patterns so users can transfer their knowledge
+ between services.
+
+
+
+
+
Typography
+
+ Typography creates hierarchy and rhythm in our interfaces. We use the Acumin Pro font family
+ for headings and body text across all services.
+
+
+
Type scale
+
+ Our type scale is based on a modular scale that ensures consistent proportions between
+ heading levels and body text. Use these sizes through design tokens:
+
+
+
+
--goa-typography-heading-xl - Page titles
+
--goa-typography-heading-l - Section headings
+
--goa-typography-heading-m - Subsection headings
+
--goa-typography-body-l - Lead paragraphs
+
--goa-typography-body-m - Body text
+
--goa-typography-body-s - Captions and labels
+
+
+
+
Color
+
+ Our color palette is designed to meet WCAG 2.1 AA contrast requirements while maintaining
+ the Government of Alberta's visual identity.
+
+
+
Color categories
+
+
+
+ Brand colors: The primary blue represents the Government of Alberta brand.
+
+
+ Interactive colors: Used for links, buttons, and focusable elements.
+
+
+ Status colors: Communicate success, warning, error, and information states.
+
+
+ Greyscale: Used for text, borders, and backgrounds.
+
+
+
+
+
+ Color accessibility
+
+ All color combinations in the design system have been tested to ensure they meet or exceed
+ WCAG 2.1 AA contrast ratios. Interactive elements maintain a minimum 4.5:1 contrast ratio
+ with their backgrounds.
+
+
+
+
Spacing
+
+ Consistent spacing creates visual rhythm and helps users scan content. Our spacing scale
+ uses an 8-pixel base unit.
+
+
+
Spacing tokens
+
+ Use these tokens instead of hard-coded pixel values:
+
+
+
+
--goa-space-2xs - 4px (0.25rem)
+
--goa-space-xs - 8px (0.5rem)
+
--goa-space-s - 12px (0.75rem)
+
--goa-space-m - 16px (1rem)
+
--goa-space-l - 24px (1.5rem)
+
--goa-space-xl - 32px (2rem)
+
--goa-space-2xl - 48px (3rem)
+
--goa-space-3xl - 64px (4rem)
+
+
+
+
Accessibility
+
+ All Government of Alberta digital services must meet WCAG 2.1 Level AA requirements.
+ The design system is built with accessibility as a core requirement, not an afterthought.
+
+
+ We are actively updating components to meet WCAG 2.2 requirements as they become the
+ standard for government digital services.
+
+
diff --git a/docs/src/pages/get-started/index.astro b/docs/src/pages/get-started/index.astro
new file mode 100644
index 0000000000..964c8a619b
--- /dev/null
+++ b/docs/src/pages/get-started/index.astro
@@ -0,0 +1,121 @@
+---
+/**
+ * Get Started - Landing Page
+ *
+ * Placeholder demonstrating the DocumentationPageLayout template.
+ * Content will be migrated from existing documentation in Brief 30.
+ */
+import DocumentationPageLayout from '../../layouts/DocumentationPageLayout.astro';
+---
+
+
+ Get started with the design system
+
+ Start with the design system to build on the research and experience of other service teams
+ and avoid repeating work that's already been done.
+
+
+
+ This page demonstrates the documentation template. Actual content from the current
+ design system website will be migrated here in a future update.
+
+
+ The design system can save you time and effort getting to a better service, allowing you to
+ focus on other high-value work. By starting with the design system, you can:
+
+
+
+
+ Streamline collaboration: Your developers can use the corresponding coded
+ design system components.
+
+
+ Ensure better accessibility: Accessibility is built into the components
+ from both design and code.
+
+
+ Save time on testing: Components have been rigorously tested across
+ various devices, browsers, and service contexts.
+
+
+ Maintain consistency: Components are coordinated with the rest of the
+ system for a cohesive experience.
+
+
+
+
+
More time for high-value work
+
+ Leveraging what exists in the design system saves you time, enabling you to spend more time
+ on other high-value tasks such as:
+
+
+
+
Usability testing
+
User research
+
Content design
+
Accessibility auditing
+
Design integrity of the product
+
Low fidelity design and testing
+
+
+
+
How do I use the design system?
+
+ Start by using the design system components and
+ patterns. You should expect that this will cover about 80% of your
+ needs in a service. When usability testing shows that a new solution is needed, design a
+ better solution.
+
+
+
+
Use the design system as the default first solution in design and development
+
Identify any needs that don't exist in the design system through user testing
+
Talk to the design system team to see what's available and what other teams have done
+
Test a better solution with users
+
Share learnings from design and development back to the design system
+
+
+
+
For designers
+
+ Get started by connecting to the GoA Figma libraries. The component library contains all
+ design system components with their variants and states. Use these components in your designs
+ to maintain consistency and enable smooth developer handoff.
+
+
+ Figma resources
+
+ Connect to the GoA Styles Library and Component Library in Figma to access all design
+ system assets.
+
+
+
+
For developers
+
+ Install the design system packages for your framework. The design system supports React,
+ Angular, and Web Components.
+
+
+
+ Import the design tokens CSS and start using components. All components follow the naming
+ convention Goab* for React and goa-* for Web Components.
+
+
+
Governance process
+
+ When you need something that doesn't exist in the design system, follow the governance
+ process to either request an addition or document your custom solution.
+
+
+ Avoid custom solutions without a genuine user need to prevent unnecessary work and save time.
+
+
diff --git a/docs/src/pages/index.astro b/docs/src/pages/index.astro
new file mode 100644
index 0000000000..4542a3ac3e
--- /dev/null
+++ b/docs/src/pages/index.astro
@@ -0,0 +1,346 @@
+---
+/**
+ * Home Page
+ *
+ * Landing page for the GoA Design System documentation site.
+ * Ported from ds-evo-website reference repo.
+ */
+import HomeLayout from '../layouts/HomeLayout.astro';
+import CardLite from '../components/CardLite.astro';
+---
+
+
+
+
+
+
+
+
+
+
Introducing the New Design System
+
+ Build on the research and experience of other service teams by using the DDD components and templates.
+
+
+
+
+
+
+
+
+
+
+
+
Build your service using the design system
+
+ Our accessible, brand-compliant components and templates help you launch faster while staying aligned with the current standard.
+
+ Conduct research with your users to validate your design decisions. Test your assumptions, gather insights, and ensure your service meets real user needs.
+
+
+
+
+
+
+
+
+
Understand your service
+
+ Complete activities to better understand the service you are designing for. Identify common users, pages, and service types within your digital service.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/pages/tokens/index.astro b/docs/src/pages/tokens/index.astro
new file mode 100644
index 0000000000..f22b4505a0
--- /dev/null
+++ b/docs/src/pages/tokens/index.astro
@@ -0,0 +1,62 @@
+---
+/**
+ * /tokens - Design Tokens Page
+ *
+ * Displays all GoA design tokens in a searchable, filterable, groupable grid.
+ */
+
+import TokensLayout from '../../layouts/TokensLayout.astro';
+import { TokensGrid } from '../../components/TokensGrid';
+import { getAllTokens, getFilterGroups } from '../../lib/tokens';
+
+// Get all tokens at build time
+const tokens = getAllTokens();
+const filterGroups = getFilterGroups();
+
+// Page metadata
+const title = 'Design Tokens';
+const description = 'Browse all GoA design tokens including colors, spacing, typography, and more.';
+---
+
+
+
+
+
Design Tokens
+
+ Design tokens are the foundational values that define the visual design of the GoA Design System.
+ Use these tokens in your CSS to ensure consistency across applications.
+
+
+
+
+
+
+
+
diff --git a/docs/src/scripts/load-web-components.ts b/docs/src/scripts/load-web-components.ts
new file mode 100644
index 0000000000..8147e5a23a
--- /dev/null
+++ b/docs/src/scripts/load-web-components.ts
@@ -0,0 +1,3 @@
+// Load GoA Web Components
+// This script registers all the custom elements
+import '@abgov/web-components';
diff --git a/docs/src/scripts/mobile-bridge.ts b/docs/src/scripts/mobile-bridge.ts
new file mode 100644
index 0000000000..e8f02d52db
--- /dev/null
+++ b/docs/src/scripts/mobile-bridge.ts
@@ -0,0 +1,135 @@
+/**
+ * Mobile Bridge Script
+ *
+ * Bridges React navigation state to page-level CSS via body attributes.
+ * This enables Astro layouts to respond to menu state changes from React components.
+ *
+ * Body attributes set:
+ * - data-mobile: "true" | "false" (viewport width < 624px)
+ * - data-menu-open: "true" | "false" (sidebar menu state)
+ * - data-header-hidden: "true" | "false" (header hidden on scroll down)
+ *
+ * Custom events listened for:
+ * - goa-menu-change: { detail: { isOpen: boolean } }
+ * - goa-menu-open: (no detail, triggers menu open)
+ */
+
+const MOBILE_BREAKPOINT = 624;
+const SIDEBAR_EXPANDED = 280;
+const SIDEBAR_COLLAPSED = 72;
+const SCROLL_UP_THRESHOLD = 10; // pixels of upward scroll to show header
+const SCROLL_DOWN_THRESHOLD = 50; // pixels from top before header can hide
+
+let lastScrollY = 0;
+let headerHidden = false;
+
+/**
+ * Update body[data-mobile] attribute based on viewport width
+ */
+function updateMobileState(): void {
+ const isMobile = window.innerWidth < MOBILE_BREAKPOINT;
+ document.body.setAttribute('data-mobile', String(isMobile));
+
+ // Sync sidebar width CSS variable for layout
+ if (isMobile) {
+ document.documentElement.style.setProperty('--sidebar-width', '0px');
+ } else {
+ // Desktop: check saved menu state for correct width
+ const saved = localStorage.getItem('goa-ds-menu-open');
+ const isOpen = saved === null ? true : saved === 'true';
+ const width = isOpen ? SIDEBAR_EXPANDED : SIDEBAR_COLLAPSED;
+ document.documentElement.style.setProperty('--sidebar-width', `${width}px`);
+ }
+
+ // Auto-close menu when resizing to desktop
+ if (!isMobile) {
+ document.body.setAttribute('data-menu-open', 'false');
+ // Reset header visibility on desktop
+ document.body.setAttribute('data-header-hidden', 'false');
+ headerHidden = false;
+ }
+}
+
+/**
+ * Handle scroll direction to show/hide mobile header
+ * - Scrolling down (past threshold): hide header
+ * - Scrolling up (any amount): show header
+ */
+function handleScroll(): void {
+ // Only apply on mobile
+ if (window.innerWidth >= MOBILE_BREAKPOINT) return;
+
+ const currentScrollY = window.scrollY;
+ const scrollDelta = currentScrollY - lastScrollY;
+
+ // Near top of page - always show header
+ if (currentScrollY < SCROLL_DOWN_THRESHOLD) {
+ if (headerHidden) {
+ headerHidden = false;
+ document.body.setAttribute('data-header-hidden', 'false');
+ }
+ }
+ // Scrolling down - hide header
+ else if (scrollDelta > 0 && !headerHidden) {
+ headerHidden = true;
+ document.body.setAttribute('data-header-hidden', 'true');
+ }
+ // Scrolling up past threshold - show header
+ else if (scrollDelta < -SCROLL_UP_THRESHOLD && headerHidden) {
+ headerHidden = false;
+ document.body.setAttribute('data-header-hidden', 'false');
+ }
+
+ lastScrollY = currentScrollY;
+}
+
+/**
+ * Handle menu state change events from React components
+ */
+function handleMenuChange(event: Event): void {
+ const customEvent = event as CustomEvent<{ isOpen: boolean }>;
+ const isOpen = customEvent.detail?.isOpen ?? false;
+ document.body.setAttribute('data-menu-open', String(isOpen));
+
+ // Update sidebar width CSS variable (desktop only)
+ if (window.innerWidth >= MOBILE_BREAKPOINT) {
+ const width = isOpen ? SIDEBAR_EXPANDED : SIDEBAR_COLLAPSED;
+ document.documentElement.style.setProperty('--sidebar-width', `${width}px`);
+ }
+
+ // Always show header when menu is open
+ if (isOpen && headerHidden) {
+ headerHidden = false;
+ document.body.setAttribute('data-header-hidden', 'false');
+ }
+}
+
+/**
+ * Initialize the mobile bridge
+ */
+function init(): void {
+ // Set initial states
+ updateMobileState();
+ document.body.setAttribute('data-menu-open', 'false');
+ document.body.setAttribute('data-header-hidden', 'false');
+ lastScrollY = window.scrollY;
+
+ // Listen for viewport changes
+ window.addEventListener('resize', updateMobileState);
+
+ // Listen for scroll (passive for performance)
+ window.addEventListener('scroll', handleScroll, { passive: true });
+
+ // Listen for menu state changes from React
+ window.addEventListener('goa-menu-change', handleMenuChange);
+}
+
+// Initialize when DOM is ready
+if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', init);
+} else {
+ init();
+}
+
+// Export for TypeScript module resolution
+export {};
diff --git a/docs/src/types/web-components.d.ts b/docs/src/types/web-components.d.ts
new file mode 100644
index 0000000000..7e7fbf9766
--- /dev/null
+++ b/docs/src/types/web-components.d.ts
@@ -0,0 +1 @@
+declare module '@abgov/web-components';
diff --git a/docs/tsconfig.json b/docs/tsconfig.json
new file mode 100644
index 0000000000..41c67ee5da
--- /dev/null
+++ b/docs/tsconfig.json
@@ -0,0 +1,18 @@
+{
+ "extends": "astro/tsconfigs/strict",
+ "compilerOptions": {
+ "baseUrl": ".",
+ "paths": {
+ "@/*": [
+ "./src/*"
+ ],
+ "@abgov/web-components": ["../dist/libs/web-components/"],
+ "@abgov/ui-components-common": ["../libs/common/src/index.ts"],
+ "@abgov/react-components": ["../libs/react-components/src/index.ts"],
+ "@abgov/react-components/experimental": ["../libs/react-components/src/experimental/index.ts"],
+ "@abgov/style": ["../dist/libs/web-components/index.css"]
+ },
+ "jsx": "react-jsx",
+ "jsxImportSource": "react"
+ }
+}
\ No newline at end of file
diff --git a/libs/angular-components/src/experimental/.eslintrc.json b/libs/angular-components/src/experimental/.eslintrc.json
new file mode 100644
index 0000000000..11f5d77431
--- /dev/null
+++ b/libs/angular-components/src/experimental/.eslintrc.json
@@ -0,0 +1,25 @@
+{
+ "overrides": [
+ {
+ "files": ["*.ts"],
+ "rules": {
+ "@angular-eslint/directive-selector": [
+ "error",
+ {
+ "type": "attribute",
+ "prefix": "goabx",
+ "style": "camelCase"
+ }
+ ],
+ "@angular-eslint/component-selector": [
+ "error",
+ {
+ "type": "element",
+ "prefix": "goabx",
+ "style": "kebab-case"
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/libs/angular-components/src/experimental/badge/badge.spec.ts b/libs/angular-components/src/experimental/badge/badge.spec.ts
new file mode 100644
index 0000000000..1ea71e751a
--- /dev/null
+++ b/libs/angular-components/src/experimental/badge/badge.spec.ts
@@ -0,0 +1,111 @@
+import { ComponentFixture, TestBed, fakeAsync, tick } from "@angular/core/testing";
+import { GoabxBadge } from "./badge";
+import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
+import { GoabBadgeType, Spacing } from "@abgov/ui-components-common";
+import { By } from "@angular/platform-browser";
+
+@Component({
+ standalone: true,
+ imports: [GoabxBadge],
+ template: `
+
+ `,
+})
+class TestBadgeComponent {
+ type?: GoabBadgeType;
+ content?: string;
+ testId?: string;
+ icon?: boolean;
+ ariaLabel?: string;
+ mt?: Spacing;
+ mb?: Spacing;
+ ml?: Spacing;
+ mr?: Spacing;
+}
+
+@Component({
+ standalone: true,
+ imports: [GoabxBadge],
+ template: ` `,
+})
+class TestBadgeNoIconComponent {
+ type?: GoabBadgeType;
+ content?: string;
+}
+
+describe("GoABBadge", () => {
+ let fixture: ComponentFixture;
+ let component: TestBadgeComponent;
+
+ beforeEach(fakeAsync(() => {
+ TestBed.configureTestingModule({
+ imports: [GoabxBadge, TestBadgeComponent, TestBadgeNoIconComponent],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ }).compileComponents();
+ }));
+
+ it("should render and set the props correctly", fakeAsync(() => {
+ fixture = TestBed.createComponent(TestBadgeComponent);
+ component = fixture.componentInstance;
+ component.type = "information";
+ component.content = "Information";
+ component.icon = true;
+ component.ariaLabel = "123";
+ component.testId = "test-id";
+ component.mt = "xs" as Spacing;
+ component.mb = "m" as Spacing;
+ component.ml = "l" as Spacing;
+ component.mr = "xl" as Spacing;
+
+ fixture.detectChanges();
+ tick();
+ fixture.detectChanges();
+ const badgeElement = fixture.debugElement.query(By.css("goa-badge")).nativeElement;
+ expect(badgeElement.getAttribute("type")).toBe("information");
+ expect(badgeElement.getAttribute("content")).toBe("Information");
+ expect(badgeElement.getAttribute("icon")).toBe("true");
+ expect(badgeElement.getAttribute("arialabel")).toBe("123");
+ expect(badgeElement.getAttribute("testid")).toBe("test-id");
+ expect(badgeElement.getAttribute("mt")).toBe(component.mt);
+ expect(badgeElement.getAttribute("mb")).toBe(component.mb);
+ expect(badgeElement.getAttribute("ml")).toBe(component.ml);
+ expect(badgeElement.getAttribute("mr")).toBe(component.mr);
+ }));
+
+ it("should not set icon attribute by default (icon undefined)", fakeAsync(() => {
+ const noIconFixture = TestBed.createComponent(TestBadgeNoIconComponent);
+ const noIconComponent = noIconFixture.componentInstance;
+ noIconComponent.type = "information";
+ noIconComponent.content = "Information";
+ noIconFixture.detectChanges();
+ tick();
+ noIconFixture.detectChanges();
+ const badgeElement = noIconFixture.debugElement.query(
+ By.css("goa-badge"),
+ ).nativeElement;
+ expect(badgeElement.getAttribute("icon")).toBe("false");
+ }));
+
+ it("should not render icon when icon is false", fakeAsync(() => {
+ fixture = TestBed.createComponent(TestBadgeComponent);
+ component = fixture.componentInstance;
+ component.type = "information";
+ component.content = "Information";
+ component.icon = false;
+ fixture.detectChanges();
+ tick();
+ fixture.detectChanges();
+ const badgeElement = fixture.debugElement.query(By.css("goa-badge")).nativeElement;
+ expect(badgeElement.getAttribute("icon")).toBe("false");
+ }));
+});
diff --git a/libs/angular-components/src/experimental/badge/badge.ts b/libs/angular-components/src/experimental/badge/badge.ts
new file mode 100644
index 0000000000..ea69ec5dab
--- /dev/null
+++ b/libs/angular-components/src/experimental/badge/badge.ts
@@ -0,0 +1,75 @@
+import {
+ GoabxBadgeType,
+ GoabIconType,
+ GoabBadgeSize,
+ GoabBadgeEmphasis,
+} from "@abgov/ui-components-common";
+import {
+ CUSTOM_ELEMENTS_SCHEMA,
+ Component,
+ Input,
+ booleanAttribute,
+ OnInit,
+ ChangeDetectorRef,
+} from "@angular/core";
+import { CommonModule } from "@angular/common";
+import { GoabBaseComponent } from "../base.component";
+
+@Component({
+ standalone: true,
+ selector: "goabx-badge",
+ template: `
+
+
+ `,
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ imports: [CommonModule],
+ styles: [
+ `
+ :host {
+ display: contents;
+ }
+ `,
+ ],
+})
+export class GoabxBadge extends GoabBaseComponent implements OnInit {
+ @Input() type?: GoabxBadgeType;
+ @Input() content?: string;
+ // Ensure boolean input; attribute only set when true so default behaviour is false
+ @Input({ transform: booleanAttribute }) icon?: boolean;
+ @Input() iconType?: GoabIconType;
+ @Input() size?: GoabBadgeSize = "medium";
+ @Input() emphasis?: GoabBadgeEmphasis = "strong";
+ @Input() ariaLabel?: string;
+
+ isReady = false;
+ version = "2";
+
+ constructor(private cdr: ChangeDetectorRef) {
+ super();
+ }
+
+ ngOnInit(): void {
+ // For Angular 20, we need to delay rendering the web component
+ // to ensure all attributes are properly bound before the component initializes
+ setTimeout(() => {
+ this.isReady = true;
+ this.cdr.detectChanges();
+ }, 0);
+ }
+}
diff --git a/libs/angular-components/src/experimental/base.component.ts b/libs/angular-components/src/experimental/base.component.ts
new file mode 100644
index 0000000000..74768456f3
--- /dev/null
+++ b/libs/angular-components/src/experimental/base.component.ts
@@ -0,0 +1,176 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
+import { Spacing } from "@abgov/ui-components-common";
+import {
+ booleanAttribute,
+ Component,
+ Input,
+ ElementRef,
+ ViewChild,
+ Renderer2,
+} from "@angular/core";
+import { ControlValueAccessor } from "@angular/forms";
+
+@Component({
+ standalone: true,
+ template: ``, //** IMPLEMENT IN SUBCLASS
+})
+export abstract class GoabBaseComponent {
+ @Input() mt?: Spacing;
+ @Input() mb?: Spacing;
+ @Input() ml?: Spacing;
+ @Input() mr?: Spacing;
+ @Input() testId?: string;
+}
+
+@Component({
+ standalone: true,
+ template: ``, //** IMPLEMENT IN SUBCLASS
+})
+/**
+ * An abstract base class that extends `GoabBaseComponent` and implements the `ControlValueAccessor` interface.
+ * This class provides a foundation for creating custom form controls in Angular, enabling them to integrate
+ * seamlessly with Angular forms. It includes support for handling value changes, touch events, and disabled states.
+ *
+ * ## Features
+ * - Supports `disabled="true"` and `error="true` attribute bindings for convenience.
+ * - Handles form control value changes and touch events via `ControlValueAccessor` methods.
+ * - Allows for flexible value types (`unknown`), making it suitable for various data types like integers, dates, or booleans.
+ * - Uses ViewChild to capture a reference to the native GOA web component element via `#goaComponentRef`.
+ * - Uses Renderer2 for safe DOM manipulation (compatible with SSR and security best practices).
+ *
+ * ## Usage
+ * Extend this class to create custom form controls. Child components must:
+ * 1. Add `#goaComponentRef` template reference to their `goa-*` element in the template
+ * 2. Inject `Renderer2` in their constructor and pass it to `super(renderer)`
+ *
+ * ### Example:
+ * ```typescript
+ * @Component({
+ * template: ``
+ * })
+ * export class GoabInput extends GoabControlValueAccessor {
+ * constructor(private cdr: ChangeDetectorRef, renderer: Renderer2) {
+ * super(renderer); // Required: pass Renderer2 to base class
+ * }
+ * }
+ * ```
+ *
+ * ## Properties
+ * - `id?`: An optional identifier for the component.
+ * - `disabled?`: A boolean indicating whether the component is disabled.
+ * - `error?`: A boolean indicating whether the component is in an error state.
+ * - `value?`: The current value of the component, which can be of any type.
+ *
+ * ## Methods
+ * - `markAsTouched()`: Marks the component as touched and triggers the `fcTouched` callback if defined.
+ * - `writeValue(value: unknown)`: Writes a new value to the form control (can be overridden for special behavior like checkbox).
+ * - `registerOnChange(fn: any)`: Registers a function to handle changes in the form control value.
+ * - `registerOnTouched(fn: any)`: Registers a function to handle touch events on the form control.
+ * - `setDisabledState?(isDisabled: boolean)`: Sets the disabled state of the component.
+ * - `convertValueToString(value: unknown)`: Converts a value to a string for DOM attribute assignment (can be overridden).
+ *
+ * ## Callbacks
+ * - `fcChange?`: A function to handle changes in the form control value.
+ * - `fcTouched?`: A function to handle touch events on the form control.
+ */
+export abstract class GoabControlValueAccessor
+ extends GoabBaseComponent
+ implements ControlValueAccessor
+{
+ @Input() id?: string;
+ // supports disabled="true" instead of [disabled]="true"
+ @Input({ transform: booleanAttribute }) public disabled?: boolean;
+ // supports error="true" instead of [error]="true"
+ @Input({ transform: booleanAttribute }) public error?: boolean;
+ // this should be unknown (not string) as it might be an integer or a date or a boolean
+ @Input() value?: unknown | null | undefined;
+
+ // implement ControlValueAccessor
+
+ /**
+ * Function to handle changes in the form control value.
+ * @param {unknown} value - The new value.
+ */
+ public fcChange?: (value: unknown) => void;
+
+ /**
+ * Function to handle touch events on the form control.
+ */
+ public fcTouched?: () => unknown;
+
+ private touched = false;
+
+ /**
+ * Marks the component as touched. If the component is not already marked as touched,
+ * it triggers the `fcTouched` callback (if defined) and sets the `touched` property to `true`.
+ */
+ public markAsTouched() {
+ if (!this.touched) {
+ this.fcTouched?.();
+ this.touched = true;
+ }
+ }
+
+ /**
+ * Reference to the native GOA web component element.
+ * Child templates should declare `#goaComponentRef` on the `goa-*` element.
+ * The base class captures it here so children don't need their own ViewChild.
+ */
+ @ViewChild("goaComponentRef", { static: false, read: ElementRef })
+ protected goaComponentRef?: ElementRef;
+
+ constructor(protected renderer: Renderer2) {
+ super();
+ }
+
+ /**
+ * Convert an arbitrary value into a string for DOM attribute assignment.
+ * Child classes can override when they need special formatting.
+ * @param value The value to convert
+ * @returns string representation or empty string for nullish/empty
+ */
+ protected convertValueToString(value: unknown): string {
+ if (value === null || value === undefined || value === "") {
+ return "";
+ }
+ return String(value);
+ }
+
+ /**
+ * Writes a new value to the form control.
+ * @param {unknown} value - The value to write.
+ */
+ public writeValue(value: unknown): void {
+ this.value = value;
+ const el = this.goaComponentRef?.nativeElement as HTMLElement | undefined;
+ if (el) {
+ const stringValue = this.convertValueToString(value);
+ this.renderer.setAttribute(el, "value", stringValue);
+ }
+ }
+
+ /**
+ * Registers a function to call when the form control value changes.
+ * @param {function} fn - The function to call.
+ */
+ public registerOnChange(fn: any): void {
+ this.fcChange = fn;
+ }
+
+ /**
+ * Registers a function to call when the form control is touched.
+ * @param {function} fn - The function to call.
+ */
+ public registerOnTouched(fn: any): void {
+ this.fcTouched = fn;
+ }
+
+ /**
+ * Sets the disabled state of the component.
+ *
+ * @param isDisabled - A boolean indicating whether the component should be disabled.
+ */
+ public setDisabledState?(isDisabled: boolean): void {
+ this.disabled = isDisabled;
+ }
+}
diff --git a/libs/angular-components/src/experimental/button/button.spec.ts b/libs/angular-components/src/experimental/button/button.spec.ts
new file mode 100644
index 0000000000..c8cecded41
--- /dev/null
+++ b/libs/angular-components/src/experimental/button/button.spec.ts
@@ -0,0 +1,98 @@
+import { ComponentFixture, TestBed, fakeAsync, tick } from "@angular/core/testing";
+import { GoabxButton } from "./button";
+import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
+import { GoabButtonSize, GoabButtonVariant, GoabIconType, Spacing, GoabButtonType } from "@abgov/ui-components-common";
+import { By } from "@angular/platform-browser";
+import { fireEvent } from "@testing-library/dom";
+
+@Component({
+ standalone: true,
+ imports: [GoabxButton],
+ template: `
+
+ {{buttonText}}
+
+ `
+})
+class TestButtonComponent{
+ type?: GoabButtonType;
+ size?: GoabButtonSize;
+ variant?: GoabButtonVariant;
+ disabled?: boolean;
+ leadingIcon?: GoabIconType;
+ trailingIcon?: GoabIconType;
+ testId?: string;
+ mt?: Spacing;
+ mb?: Spacing;
+ ml?: Spacing;
+ mr?: Spacing;
+ buttonText?: string;
+
+ onClick() {
+ /* do nothing */
+ }
+
+}
+
+describe("GoABButton", () => {
+ let fixture: ComponentFixture;
+ let component: TestButtonComponent;
+
+ beforeEach(fakeAsync(() => {
+ TestBed.configureTestingModule({
+ imports: [GoabxButton, TestButtonComponent],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(TestButtonComponent);
+ component = fixture.componentInstance;
+ component.buttonText = "Click me";
+ component.type = "primary";
+ component.size = "compact";
+ component.variant = "destructive";
+ component.leadingIcon = "car";
+ component.trailingIcon = "bag";
+ component.mt = "s";
+ component.mr = "m";
+ component.mb = "l";
+ component.ml = "xl";
+ fixture.detectChanges();
+ tick();
+ fixture.detectChanges();
+ }));
+
+ it("should render the properties", () => {
+ const buttonElement = fixture.debugElement.query(By.css("goa-button")).nativeElement;
+ expect(buttonElement.getAttribute("type")).toBe("primary");
+ expect(buttonElement.getAttribute("size")).toBe("compact");
+ expect(buttonElement.getAttribute("variant")).toBe("destructive");
+ expect(buttonElement.getAttribute("leadingicon")).toBe("car");
+ expect(buttonElement.getAttribute("trailingicon")).toBe("bag");
+ expect(buttonElement.getAttribute("mt")).toBe("s");
+ expect(buttonElement.getAttribute("mr")).toBe("m");
+ expect(buttonElement.getAttribute("mb")).toBe("l");
+ expect(buttonElement.getAttribute("ml")).toBe("xl");
+ // it should render the content
+ expect(buttonElement.textContent).toContain("Click me");
+ });
+
+ it("should respond to click event", fakeAsync(() => {
+ const onClick = jest.spyOn(component, "onClick");
+ const buttonElement = fixture.debugElement.query(By.css("goa-button")).nativeElement;
+
+ fireEvent(buttonElement, new CustomEvent("_click"));
+ expect(onClick).toHaveBeenCalled();
+ }))
+})
diff --git a/libs/angular-components/src/experimental/button/button.ts b/libs/angular-components/src/experimental/button/button.ts
new file mode 100644
index 0000000000..02bfaf735c
--- /dev/null
+++ b/libs/angular-components/src/experimental/button/button.ts
@@ -0,0 +1,85 @@
+import {
+ GoabButtonSize,
+ GoabButtonType,
+ GoabButtonVariant,
+ GoabIconType,
+} from "@abgov/ui-components-common";
+import {
+ CUSTOM_ELEMENTS_SCHEMA,
+ Component,
+ EventEmitter,
+ Input,
+ Output,
+ booleanAttribute,
+ OnInit,
+ ChangeDetectorRef,
+} from "@angular/core";
+import { CommonModule } from "@angular/common";
+import { GoabBaseComponent } from "../base.component";
+
+@Component({
+ standalone: true,
+ selector: "goabx-button",
+ imports: [CommonModule],
+ template: `
+
+
+
+ `,
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+})
+export class GoabxButton extends GoabBaseComponent implements OnInit {
+ @Input() type?: GoabButtonType = "primary";
+ @Input() size?: GoabButtonSize;
+ @Input() variant?: GoabButtonVariant;
+ @Input({ transform: booleanAttribute }) disabled?: boolean;
+ @Input() leadingIcon?: GoabIconType;
+ @Input() trailingIcon?: GoabIconType;
+ @Input() width?: string;
+ @Input() action?: string;
+ @Input() actionArg?: string;
+ @Input() actionArgs?: Record;
+
+ @Output() onClick = new EventEmitter();
+
+ isReady = false;
+ version = "2";
+
+ constructor(private cdr: ChangeDetectorRef) {
+ super();
+ }
+
+ ngOnInit(): void {
+ // For Angular 20, we need to delay rendering the web component
+ // to ensure all attributes are properly bound before the component initializes
+ setTimeout(() => {
+ this.isReady = true;
+ this.cdr.detectChanges();
+ }, 0);
+ }
+
+ _onClick() {
+ this.onClick.emit();
+ }
+
+ protected readonly JSON = JSON;
+}
diff --git a/libs/angular-components/src/experimental/calendar/calendar.spec.ts b/libs/angular-components/src/experimental/calendar/calendar.spec.ts
new file mode 100644
index 0000000000..5666f2881e
--- /dev/null
+++ b/libs/angular-components/src/experimental/calendar/calendar.spec.ts
@@ -0,0 +1,96 @@
+import { ComponentFixture, TestBed, fakeAsync, tick } from "@angular/core/testing";
+import { GoabxCalendar } from "./calendar";
+import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
+import { fireEvent } from "@testing-library/dom";
+import { GoabCalendarOnChangeDetail, Spacing } from "@abgov/ui-components-common";
+
+@Component({
+ standalone: true,
+ imports: [GoabxCalendar],
+ template: `
+
+
+ `,
+})
+class TestCalendarComponent {
+ name?: string;
+ value?: Date;
+ min?: Date;
+ max?: Date;
+ testId?: string;
+ mt?: Spacing;
+ mb?: Spacing;
+ ml?: Spacing;
+ mr?: Spacing;
+
+ onChange(event: GoabCalendarOnChangeDetail) {
+ /* do nothing */
+ }
+}
+
+describe("GoABCalendar", () => {
+ let fixture: ComponentFixture;
+ let component: TestCalendarComponent;
+ beforeEach(fakeAsync(() => {
+ TestBed.configureTestingModule({
+ imports: [GoabxCalendar, TestCalendarComponent],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(TestCalendarComponent);
+ component = fixture.componentInstance;
+
+ component.name = "calendar";
+ component.value = new Date();
+ component.min = new Date();
+ component.max = new Date();
+ component.testId = "test-calendar";
+ component.mt = "m";
+ component.mb = "xl";
+ component.ml = "s";
+ component.mr = "l";
+ fixture.detectChanges();
+ tick();
+ fixture.detectChanges();
+ }));
+
+ it("should render properties", () => {
+ const calendar = fixture.nativeElement.querySelector("goa-calendar");
+ expect(calendar.getAttribute("name")).toBe(component.name);
+ expect(calendar.getAttribute("min")).toBe(component.min?.toString());
+ expect(calendar.getAttribute("max")).toBe(component.max?.toString());
+ expect(calendar.getAttribute("testid")).toBe(component.testId);
+ expect(calendar.getAttribute("mt")).toBe(component.mt);
+ expect(calendar.getAttribute("mb")).toBe(component.mb);
+ expect(calendar.getAttribute("ml")).toBe(component.ml);
+ expect(calendar.getAttribute("mr")).toBe(component.mr);
+ });
+
+ it("should handle the event", () => {
+ const onChange = jest.spyOn(component, "onChange");
+ const calendar = fixture.nativeElement.querySelector("goa-calendar");
+
+ fireEvent(
+ calendar,
+ new CustomEvent("_change", {
+ detail: {
+ type: "date",
+ value: new Date(),
+ name: component.name,
+ },
+ }),
+ );
+ expect(onChange).toHaveBeenCalled();
+ });
+});
diff --git a/libs/angular-components/src/experimental/calendar/calendar.ts b/libs/angular-components/src/experimental/calendar/calendar.ts
new file mode 100644
index 0000000000..418fdf6e68
--- /dev/null
+++ b/libs/angular-components/src/experimental/calendar/calendar.ts
@@ -0,0 +1,67 @@
+import { GoabCalendarOnChangeDetail } from "@abgov/ui-components-common";
+import {
+ CUSTOM_ELEMENTS_SCHEMA,
+ Component,
+ EventEmitter,
+ Input,
+ Output,
+ OnInit,
+ ChangeDetectorRef,
+} from "@angular/core";
+import { CommonModule } from "@angular/common";
+import { GoabBaseComponent } from "../base.component";
+
+@Component({
+ standalone: true,
+ selector: "goabx-calendar",
+ imports: [CommonModule],
+ template: `
+
+
+
+ `,
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+})
+export class GoabxCalendar extends GoabBaseComponent implements OnInit {
+ version = 2;
+
+ @Input() name?: string;
+ @Input() value?: Date;
+ @Input() min?: Date;
+ @Input() max?: Date;
+
+ @Output() onChange = new EventEmitter();
+
+ isReady = false;
+
+ constructor(private cdr: ChangeDetectorRef) {
+ super();
+ }
+
+ ngOnInit(): void {
+ // For Angular 20, we need to delay rendering the web component
+ // to ensure all attributes are properly bound before the component initializes
+ setTimeout(() => {
+ this.isReady = true;
+ this.cdr.detectChanges();
+ }, 0);
+ }
+
+ _onChange(e: Event) {
+ const details = (e as CustomEvent).detail;
+ this.onChange.emit(details);
+ }
+}
diff --git a/libs/angular-components/src/experimental/callout/callout.spec.ts b/libs/angular-components/src/experimental/callout/callout.spec.ts
new file mode 100644
index 0000000000..1ad7bb3201
--- /dev/null
+++ b/libs/angular-components/src/experimental/callout/callout.spec.ts
@@ -0,0 +1,80 @@
+import { ComponentFixture, TestBed, fakeAsync, tick } from "@angular/core/testing";
+import { GoabxCallout } from "./callout";
+import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
+import { GoabCalloutSize, GoabCalloutType, Spacing } from "@abgov/ui-components-common";
+
+@Component({
+ standalone: true,
+ imports: [GoabxCallout],
+ template: `
+
+ Information to the user goes in the content. Information can include markup as
+ desired.
+
+ `,
+})
+class TestCalloutComponent {
+ type?: GoabCalloutType;
+ heading?: string;
+ size?: GoabCalloutSize;
+ testId?: string;
+ mt?: Spacing;
+ mb?: Spacing;
+ ml?: Spacing;
+ mr?: Spacing;
+}
+
+describe("GoABCallout", () => {
+ let fixture: ComponentFixture;
+ let component: TestCalloutComponent;
+
+ beforeEach(fakeAsync(() => {
+ TestBed.configureTestingModule({
+ imports: [GoabxCallout, TestCalloutComponent],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(TestCalloutComponent);
+ component = fixture.componentInstance;
+
+ component.type = "information";
+ component.heading = "Callout Title";
+ component.size = "medium";
+ component.testId = "test-callout";
+ component.mt = "s";
+ component.mr = "m";
+ component.mb = "l";
+ component.ml = "xl";
+ fixture.detectChanges();
+ tick();
+ fixture.detectChanges();
+ }));
+
+ it("should render properties", () => {
+ const el = fixture.nativeElement.querySelector("goa-callout");
+ expect(el.getAttribute("heading")).toContain(component.heading);
+ expect(el.getAttribute("type")).toContain(component.type);
+ expect(el.getAttribute("size")).toContain(component.size);
+ expect(el.getAttribute("testid")).toContain(component.testId);
+ expect(el.getAttribute("maxwidth")).toContain("480px");
+ expect(el.getAttribute("mt")).toBe(component.mt);
+ expect(el.getAttribute("mr")).toBe(component.mr);
+ expect(el.getAttribute("mb")).toBe(component.mb);
+ expect(el.getAttribute("ml")).toBe(component.ml);
+
+ // render children
+ expect(el.textContent).toContain(
+ "Information to the user goes in the content. Information can include markup as desired.",
+ );
+ });
+});
diff --git a/libs/angular-components/src/experimental/callout/callout.ts b/libs/angular-components/src/experimental/callout/callout.ts
new file mode 100644
index 0000000000..ea2855d53f
--- /dev/null
+++ b/libs/angular-components/src/experimental/callout/callout.ts
@@ -0,0 +1,68 @@
+import {
+ GoabCalloutAriaLive,
+ GoabCalloutSize,
+ GoabCalloutType,
+ GoabCalloutIconTheme,
+ GoabCalloutEmphasis,
+} from "@abgov/ui-components-common";
+import {
+ CUSTOM_ELEMENTS_SCHEMA,
+ Component,
+ Input,
+ OnInit,
+ ChangeDetectorRef,
+} from "@angular/core";
+import { CommonModule } from "@angular/common";
+import { GoabBaseComponent } from "../base.component";
+
+@Component({
+ standalone: true,
+ selector: "goabx-callout",
+ imports: [CommonModule],
+ template: `
+
+
+
+ `,
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+})
+export class GoabxCallout extends GoabBaseComponent implements OnInit {
+ isReady = false;
+ version = "2";
+
+ constructor(private cdr: ChangeDetectorRef) {
+ super();
+ }
+
+ ngOnInit(): void {
+ // For Angular 20, we need to delay rendering the web component
+ // to ensure all attributes are properly bound before the component initializes
+ setTimeout(() => {
+ this.isReady = true;
+ this.cdr.detectChanges();
+ }, 0);
+ }
+
+ @Input() type?: GoabCalloutType = "information";
+ @Input() heading?: string = "";
+ @Input() size?: GoabCalloutSize = "large";
+ @Input() maxWidth?: string;
+ @Input() ariaLive?: GoabCalloutAriaLive = "off";
+ @Input() iconTheme?: GoabCalloutIconTheme = "outline";
+ @Input() emphasis?: GoabCalloutEmphasis = "medium";
+}
diff --git a/libs/angular-components/src/experimental/checkbox/checkbox.spec.ts b/libs/angular-components/src/experimental/checkbox/checkbox.spec.ts
new file mode 100644
index 0000000000..2949ac63d5
--- /dev/null
+++ b/libs/angular-components/src/experimental/checkbox/checkbox.spec.ts
@@ -0,0 +1,263 @@
+import { ComponentFixture, TestBed, fakeAsync, tick } from "@angular/core/testing";
+import { GoabxCheckbox } from "./checkbox";
+import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
+import { ReactiveFormsModule } from "@angular/forms";
+import { fireEvent } from "@testing-library/dom";
+import { By } from "@angular/platform-browser";
+import { Spacing } from "@abgov/ui-components-common";
+
+@Component({
+ standalone: true,
+ imports: [GoabxCheckbox],
+ template: `
+
+
+ `,
+})
+class TestCheckboxComponent {
+ name?: string;
+ checked?: boolean;
+ text?: string;
+ value?: string | number | boolean;
+ disabled?: boolean;
+ error?: boolean;
+ ariaLabel?: string;
+ testId?: string;
+ mt?: Spacing;
+ mb?: Spacing;
+ ml?: Spacing;
+ mr?: Spacing;
+
+ onChange() {
+ /* do nothing */
+ }
+}
+
+describe("GoabxCheckbox", () => {
+ let fixture: ComponentFixture;
+ let component: TestCheckboxComponent;
+
+ beforeEach(fakeAsync(() => {
+ TestBed.configureTestingModule({
+ imports: [TestCheckboxComponent, GoabxCheckbox, ReactiveFormsModule],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(TestCheckboxComponent);
+ component = fixture.componentInstance;
+
+ component.name = "foo";
+ component.value = "bar";
+ component.text = "to display";
+ component.disabled = false;
+ component.checked = true;
+ component.error = false;
+ component.testId = "testId";
+ component.mt = "s";
+ component.mr = "m";
+ component.mb = "l";
+ component.ml = "xl";
+ fixture.detectChanges();
+ tick();
+ fixture.detectChanges();
+ }));
+
+ it("should render properties", () => {
+ const checkboxElement = fixture.debugElement.query(
+ By.css("goa-checkbox"),
+ ).nativeElement;
+ expect(checkboxElement.getAttribute("name")).toBe(component.name);
+ expect(checkboxElement.getAttribute("text")).toBe(component.text);
+ expect(checkboxElement.getAttribute("testid")).toBe(component.testId);
+ expect(checkboxElement.getAttribute("mt")).toBe(component.mt);
+ expect(checkboxElement.getAttribute("mr")).toBe(component.mr);
+ expect(checkboxElement.getAttribute("mb")).toBe(component.mb);
+ expect(checkboxElement.getAttribute("ml")).toBe(component.ml);
+ expect(checkboxElement.getAttribute("description")).toBe("Description text");
+ expect(checkboxElement.getAttribute("maxwidth")).toBe("480px");
+ });
+
+ it("should handle onChange event", async () => {
+ const onChange = jest.spyOn(component, "onChange");
+
+ const checkboxElement = fixture.debugElement.query(
+ By.css("goa-checkbox"),
+ ).nativeElement;
+
+ fireEvent(
+ checkboxElement,
+ new CustomEvent("_change", {
+ detail: { name: "foo", value: "bar", checked: true },
+ }),
+ );
+
+ expect(onChange).toHaveBeenCalled();
+ });
+
+ describe("writeValue", () => {
+ it("should set checked attribute to true when value is truthy", () => {
+ const checkboxComponent = fixture.debugElement.query(
+ By.css("goabx-checkbox"),
+ ).componentInstance;
+ const checkboxElement = fixture.debugElement.query(
+ By.css("goa-checkbox"),
+ ).nativeElement;
+
+ checkboxComponent.writeValue(true);
+ expect(checkboxElement.getAttribute("checked")).toBe("true");
+
+ checkboxComponent.writeValue("some value");
+ expect(checkboxElement.getAttribute("checked")).toBe("true");
+
+ checkboxComponent.writeValue(1);
+ expect(checkboxElement.getAttribute("checked")).toBe("true");
+ });
+
+ it("should set checked attribute to false when value is falsy", () => {
+ const checkboxComponent = fixture.debugElement.query(
+ By.css("goabx-checkbox"),
+ ).componentInstance;
+ const checkboxElement = fixture.debugElement.query(
+ By.css("goa-checkbox"),
+ ).nativeElement;
+
+ checkboxComponent.writeValue(false);
+ expect(checkboxElement.getAttribute("checked")).toBe("false");
+
+ checkboxComponent.writeValue(null);
+ expect(checkboxElement.getAttribute("checked")).toBe("false");
+
+ checkboxComponent.writeValue(undefined);
+ expect(checkboxElement.getAttribute("checked")).toBe("false");
+
+ checkboxComponent.writeValue("");
+ expect(checkboxElement.getAttribute("checked")).toBe("false");
+ });
+
+ it("should update component value property", () => {
+ const checkboxComponent = fixture.debugElement.query(
+ By.css("goabx-checkbox"),
+ ).componentInstance;
+
+ checkboxComponent.writeValue(true);
+ expect(checkboxComponent.value).toBe(true);
+
+ checkboxComponent.writeValue(null);
+ expect(checkboxComponent.value).toBe(null);
+ });
+ });
+});
+
+@Component({
+ standalone: true,
+ imports: [GoabxCheckbox],
+ template: `
+
+
+ A description slot
+
+
+ `,
+})
+class TestCheckboxWithDescriptionSlotComponent {
+ /** do nothing **/
+}
+
+describe("Checkbox with description slot", () => {
+ let fixture: ComponentFixture;
+
+ it("should render with slot description", fakeAsync(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ TestCheckboxWithDescriptionSlotComponent,
+ GoabxCheckbox,
+ ReactiveFormsModule,
+ ],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(TestCheckboxWithDescriptionSlotComponent);
+
+ fixture.detectChanges();
+ tick();
+ fixture.detectChanges();
+ const checkboxElement = fixture.debugElement.query(
+ By.css("goa-checkbox"),
+ ).nativeElement;
+ const slotDescription = checkboxElement.querySelector("[slot='description']");
+ expect(slotDescription.textContent).toContain("A description slot");
+ }));
+});
+
+@Component({
+ standalone: true,
+ imports: [GoabxCheckbox],
+ template: `
+
+
+ A reveal slot
+
+
+ `,
+})
+class TestCheckboxWithRevealSlotComponent {}
+
+describe("Checkbox with reveal slot", () => {
+ let fixture: ComponentFixture;
+
+ beforeEach(fakeAsync(() => {
+ TestBed.configureTestingModule({
+ imports: [TestCheckboxWithRevealSlotComponent, GoabxCheckbox, ReactiveFormsModule],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(TestCheckboxWithRevealSlotComponent);
+ fixture.detectChanges();
+ tick();
+ fixture.detectChanges();
+ }));
+
+ it("should render with slot reveal", () => {
+ const checkboxElement = fixture.debugElement.query(
+ By.css("goa-checkbox"),
+ ).nativeElement;
+ const slotReveal = checkboxElement.querySelector("[slot='reveal']");
+ expect(slotReveal.textContent).toContain("A reveal slot");
+ });
+
+ it("should pass the revealAriaLabel property to the web component", () => {
+ const checkboxElement = fixture.debugElement.query(
+ By.css("goa-checkbox"),
+ ).nativeElement;
+ expect(checkboxElement.getAttribute("revealarialabel")).toBe(
+ "Screen reader announcement for reveal content",
+ );
+ });
+});
diff --git a/libs/angular-components/src/experimental/checkbox/checkbox.ts b/libs/angular-components/src/experimental/checkbox/checkbox.ts
new file mode 100644
index 0000000000..72dbe2c89f
--- /dev/null
+++ b/libs/angular-components/src/experimental/checkbox/checkbox.ts
@@ -0,0 +1,130 @@
+import {
+ GoabCheckboxOnChangeDetail,
+ GoabCheckboxSize,
+} from "@abgov/ui-components-common";
+import {
+ CUSTOM_ELEMENTS_SCHEMA,
+ Component,
+ EventEmitter,
+ Input,
+ Output,
+ forwardRef,
+ TemplateRef,
+ booleanAttribute,
+ OnInit,
+ ChangeDetectorRef,
+ Renderer2,
+} from "@angular/core";
+import { NG_VALUE_ACCESSOR } from "@angular/forms";
+import { NgTemplateOutlet, CommonModule } from "@angular/common";
+import { GoabControlValueAccessor } from "../base.component";
+
+@Component({
+ standalone: true,
+ selector: "goabx-checkbox",
+ template: `
+
+
+
+
+
+
+
+ `,
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ providers: [
+ {
+ provide: NG_VALUE_ACCESSOR,
+ multi: true,
+ useExisting: forwardRef(() => GoabxCheckbox),
+ },
+ ],
+ imports: [NgTemplateOutlet, CommonModule],
+})
+export class GoabxCheckbox extends GoabControlValueAccessor implements OnInit {
+ isReady = false;
+ version = "2";
+
+ constructor(
+ private cdr: ChangeDetectorRef,
+ renderer: Renderer2,
+ ) {
+ super(renderer);
+ }
+
+ ngOnInit(): void {
+ // For Angular 20, we need to delay rendering the web component
+ // to ensure all attributes are properly bound before the component initializes
+ setTimeout(() => {
+ this.isReady = true;
+ this.cdr.detectChanges();
+ }, 0);
+ }
+
+ @Input() name?: string;
+ @Input({ transform: booleanAttribute }) checked?: boolean;
+ @Input({ transform: booleanAttribute }) indeterminate?: boolean;
+ @Input() text?: string;
+ // ** NOTE: can we just use the base component for this?
+ @Input() override value?: string | number | boolean | null;
+ @Input() ariaLabel?: string;
+ @Input() description!: string | TemplateRef;
+ @Input() reveal?: TemplateRef;
+ @Input() revealArialLabel?: string;
+ @Input() maxWidth?: string;
+ @Input() size?: GoabCheckboxSize = "default";
+
+ @Output() onChange = new EventEmitter();
+
+ getDescriptionAsString(): string {
+ return typeof this.description === "string" ? this.description : "";
+ }
+
+ getDescriptionAsTemplate(): TemplateRef | null {
+ if (this.description) {
+ return typeof this.description === "string" ? null : this.description;
+ }
+ return null;
+ }
+
+ _onChange(e: Event) {
+ const detail = { ...(e as CustomEvent).detail, event: e };
+ this.onChange.emit(detail);
+ this.markAsTouched();
+ this.fcChange?.(detail.binding === "check" ? detail.checked : detail.value || "");
+ }
+
+ // Checkbox is a special case: it uses `checked` instead of `value`.
+ override writeValue(value: string | number | boolean | null): void {
+ this.value = value;
+ this.checked = !!value;
+
+ const el = this.goaComponentRef?.nativeElement as HTMLElement | undefined;
+ if (el) {
+ this.renderer.setAttribute(el, "checked", this.checked ? "true" : "false");
+ }
+ }
+}
diff --git a/libs/angular-components/src/experimental/date-picker/date-picker.spec.ts b/libs/angular-components/src/experimental/date-picker/date-picker.spec.ts
new file mode 100644
index 0000000000..d326767f9f
--- /dev/null
+++ b/libs/angular-components/src/experimental/date-picker/date-picker.spec.ts
@@ -0,0 +1,102 @@
+import { ComponentFixture, TestBed, fakeAsync, tick } from "@angular/core/testing";
+import { GoabxDatePicker } from "./date-picker";
+import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
+import { Spacing } from "@abgov/ui-components-common";
+import { ReactiveFormsModule } from "@angular/forms";
+import { addMonths } from "date-fns";
+import { By } from "@angular/platform-browser";
+import { fireEvent } from "@testing-library/dom";
+
+@Component({
+ standalone: true,
+ imports: [GoabxDatePicker],
+ template: `
+
+ `,
+})
+class TestDatePickerComponent {
+ name?: string;
+ value?: Date | string;
+ min?: Date | string;
+ max?: Date | string;
+ error?: boolean;
+ mt?: Spacing;
+ mb?: Spacing;
+ ml?: Spacing;
+ mr?: Spacing;
+
+ onChange() {
+ /* do nothing */
+ }
+}
+
+describe("GoABDatePicker", () => {
+ let fixture: ComponentFixture;
+ let component: TestDatePickerComponent;
+
+ beforeEach(fakeAsync(() => {
+ TestBed.configureTestingModule({
+ imports: [GoabxDatePicker, ReactiveFormsModule, TestDatePickerComponent],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(TestDatePickerComponent);
+ component = fixture.componentInstance;
+ // Assign values
+ const value = new Date();
+ component.name = "foo";
+ component.min = addMonths(value, -1);
+ component.max = addMonths(value, 1);
+ component.value = value;
+ component.error = true;
+ component.mt = "l";
+ component.mb = "m";
+ component.ml = "s";
+ component.mr = "xs";
+ fixture.detectChanges();
+ tick();
+ fixture.detectChanges();
+ }));
+
+ it("should render successfully", () => {
+ const el = fixture.debugElement.query(By.css("goa-date-picker")).nativeElement;
+ expect(el).toBeTruthy();
+
+ expect(el?.getAttribute("name")).toBe(component.name);
+ expect(el?.getAttribute("value")).toBe((component.value as Date)?.toISOString());
+ expect(el?.getAttribute("error")).toBe(`${component.error}`);
+ expect(el?.getAttribute("min")).toBe(component.min?.toString());
+ expect(el?.getAttribute("max")).toBe(component.max?.toString());
+ expect(el?.getAttribute("mt")).toBe(component.mt);
+ expect(el?.getAttribute("mb")).toBe(component.mb);
+ expect(el?.getAttribute("ml")).toBe(component.ml);
+ expect(el?.getAttribute("mr")).toBe(component.mr);
+ expect(el?.getAttribute("type")).toBe("input");
+ });
+
+ it("should handle event", fakeAsync(() => {
+ const onChange = jest.spyOn(component, "onChange");
+ const el = fixture.debugElement.query(By.css("goa-date-picker")).nativeElement;
+
+ fireEvent(
+ el,
+ new CustomEvent("_change", {
+ detail: { name: component.name, value: new Date() },
+ }),
+ );
+
+ expect(onChange).toHaveBeenCalled();
+ }));
+});
diff --git a/libs/angular-components/src/experimental/date-picker/date-picker.ts b/libs/angular-components/src/experimental/date-picker/date-picker.ts
new file mode 100644
index 0000000000..edd92c0056
--- /dev/null
+++ b/libs/angular-components/src/experimental/date-picker/date-picker.ts
@@ -0,0 +1,139 @@
+import {
+ GoabDatePickerInputType,
+ GoabDatePickerOnChangeDetail,
+} from "@abgov/ui-components-common";
+import {
+ CUSTOM_ELEMENTS_SCHEMA,
+ Component,
+ EventEmitter,
+ Input,
+ Output,
+ forwardRef,
+ ElementRef,
+ HostListener,
+ OnInit,
+ ChangeDetectorRef,
+ Renderer2,
+} from "@angular/core";
+import { NG_VALUE_ACCESSOR } from "@angular/forms";
+import { CommonModule } from "@angular/common";
+import { GoabControlValueAccessor } from "../base.component";
+
+@Component({
+ standalone: true,
+ selector: "goabx-date-picker",
+ imports: [CommonModule],
+ template: `
+ `,
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ providers: [
+ {
+ provide: NG_VALUE_ACCESSOR,
+ multi: true,
+ useExisting: forwardRef(() => GoabxDatePicker),
+ },
+ ],
+})
+export class GoabxDatePicker extends GoabControlValueAccessor implements OnInit {
+ isReady = false;
+ version = 2;
+
+ @Input() name?: string;
+ @Input() override value?: Date | string | null | undefined;
+ @Input() min?: Date | string;
+ @Input() max?: Date | string;
+ @Input() type?: GoabDatePickerInputType;
+ /***
+ * @deprecated This property has no effect and will be removed in a future version
+ */
+ @Input() relative?: boolean;
+ @Input() width?: string;
+
+ @Output() onChange = new EventEmitter();
+
+ formatValue(val: Date | string | null | undefined): string {
+ if (!val) return "";
+
+ if (val instanceof Date) {
+ return val.toISOString();
+ }
+
+ return val;
+ }
+
+ _onChange(e: Event) {
+ const detail = { ...(e as CustomEvent).detail, event: e };
+ this.onChange.emit(detail);
+ this.markAsTouched();
+ this.fcChange?.(detail.value);
+ }
+
+ constructor(
+ protected elementRef: ElementRef,
+ private cdr: ChangeDetectorRef,
+ renderer: Renderer2,
+ ) {
+ super(renderer);
+ }
+
+ ngOnInit(): void {
+ // For Angular 20, we need to delay rendering the web component
+ // to ensure all attributes are properly bound before the component initializes
+ setTimeout(() => {
+ this.isReady = true;
+ this.cdr.detectChanges();
+ }, 0);
+
+ if (this.value && typeof this.value !== "string") {
+ console.warn(
+ "Using a `Date` type for value is deprecated. Instead use a string of the format `yyyy-mm-dd`",
+ );
+ }
+ }
+
+ override setDisabledState(isDisabled: boolean) {
+ this.disabled = isDisabled;
+ this.elementRef.nativeElement.disabled = isDisabled;
+ }
+
+ @HostListener("disabledChange", ["$event.detail.disabled"])
+ listenDisabledChange(isDisabled: boolean) {
+ this.setDisabledState(isDisabled);
+ }
+
+ override writeValue(value: Date | null): void {
+ this.value = value;
+
+ const datePickerEl = this.goaComponentRef?.nativeElement as HTMLElement | undefined;
+ if (datePickerEl) {
+ if (!value) {
+ this.renderer.setAttribute(datePickerEl, "value", "");
+ } else {
+ this.renderer.setAttribute(
+ datePickerEl,
+ "value",
+ value instanceof Date ? value.toISOString() : value,
+ );
+ }
+ }
+ }
+}
diff --git a/libs/angular-components/src/experimental/drawer/drawer.spec.ts b/libs/angular-components/src/experimental/drawer/drawer.spec.ts
new file mode 100644
index 0000000000..5af42fd2b0
--- /dev/null
+++ b/libs/angular-components/src/experimental/drawer/drawer.spec.ts
@@ -0,0 +1,71 @@
+import { ComponentFixture, TestBed, fakeAsync, tick } from "@angular/core/testing";
+import { GoabxDrawer } from "./drawer";
+import { Component } from "@angular/core";
+import { GoabDrawerPosition, GoabDrawerSize } from "@abgov/ui-components-common";
+
+@Component({
+ standalone: true,
+ imports: [GoabxDrawer],
+ template: `
+
+ {{ content }}
+
+