diff --git a/.env.tmpl b/.env.tmpl deleted file mode 100644 index 09d811d26..000000000 --- a/.env.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -# Get your own token to use here https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#example-usage-of-the-vars-context -# Except use tokens (classic) and not fine-grained -VITE_AUTH_TOKEN="" \ No newline at end of file diff --git a/README.md b/README.md index 53fe10b6f..ff92a0b0d 100644 --- a/README.md +++ b/README.md @@ -1 +1,20 @@ -# UI component library documentation +# Installation + +1. `npm i` +2. `npm run build` +3. `npm run dev` + +## Testing Bug Report Form + +To test the bug report form follow these steps: + +1. Create a file called `.env` in the base directoy +2. Add a line to the file `VITE_AUTH_TOKEN=""` +3. Go to [https://github.com/](github.com) + * Click your profile in the top right + * Select Settings + * Select Developer Settings on the bottom left + * Select Personal access tokens and then Tokens (classic) + * Generate new token (classic) + * Give it the `public_repo` permission (only that one) +4. Add your new token between the `""` in the line you added in step 2 \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 5333e0b02..fad7d22a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,8 @@ "name": "code-sandbox", "version": "0.0.0", "dependencies": { - "@abgov/react-components": "5.3.0", - "@abgov/web-components": "1.28.0", + "@abgov/react-components": "5.4.0", + "@abgov/web-components": "1.29.0", "@faker-js/faker": "^8.3.1", "highlight.js": "^11.8.0", "octokit": "^4.0.2", @@ -42,9 +42,9 @@ } }, "node_modules/@abgov/react-components": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@abgov/react-components/-/react-components-5.3.0.tgz", - "integrity": "sha512-AQbrEv4mMIYKThUT/lslAiZn1OtfcM2RQhMkKbRm/Y06Uf81hzkB9LhlkWw+tnWtgbRgXUTXxOxGkyQTbQ0NlA==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@abgov/react-components/-/react-components-5.4.0.tgz", + "integrity": "sha512-vN1Ktjkw5IWaeJYmf9i8gKJpjn6px7D9lEt6USg1qjQzf5IKxR28aIuowBS7M2kmJ4Vk7AP+Z1yjB2g5Pw4J3w==", "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0", "react": "^17.0.0 || ^18.0.0", @@ -52,9 +52,9 @@ } }, "node_modules/@abgov/web-components": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/@abgov/web-components/-/web-components-1.28.0.tgz", - "integrity": "sha512-0ReCvggXcDkuWT6+/sM2dNEl2a38XL2MlpZm7XCSq2P+/bCjBPVvkHwqEXj/VbwHvbHyGhsKtdSSh9rdmfggwg==", + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@abgov/web-components/-/web-components-1.29.0.tgz", + "integrity": "sha512-4Y5mzHaNjq/unrs81EP7/mjiauj9mtowNillvPIpFFTUo+9DN2XL1TKPliG0B3Z8WRSS9ayrt3KXzV1WRQh2oQ==", "peerDependencies": { "@sveltejs/vite-plugin-svelte": "3.x", "glob": "10.x", @@ -1900,9 +1900,9 @@ "dev": true }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", diff --git a/package.json b/package.json index 2d09a195f..e8b78b596 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,8 @@ "prettier": "npx prettier . --write" }, "dependencies": { - "@abgov/react-components": "5.3.0", - "@abgov/web-components": "1.28.0", + "@abgov/react-components": "5.4.0", + "@abgov/web-components": "1.29.0", "@faker-js/faker": "^8.3.1", "highlight.js": "^11.8.0", "octokit": "^4.0.2", diff --git a/src/App.tsx b/src/App.tsx index 59913c180..225523351 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -30,7 +30,6 @@ import ButtonGroupPage from "@routes/components/ButtonGroup"; import ButtonPage from "@routes/components/Button"; import CalloutPage from "@routes/components/Callout"; import CheckboxPage from "@routes/components/Checkbox"; -import ChipPage from "@routes/components/Chip"; import ComponentNotFoundPage from "@routes/not-found/NotFound"; import ContainerPage from "@routes/components/Container"; import DatePickerPage from "@routes/components/DatePicker"; @@ -38,16 +37,17 @@ import DetailsPage from "@routes/components/Details"; import DividerPage from "@routes/components/Divider"; import DropdownPage from "@routes/components/Dropdown"; import FileUploaderPage from "@routes/components/FileUploader"; +import FilterChipPage from "@routes/components/FilterChip"; import FormItemPage from "@routes/components/FormItemPage.tsx"; import FormStepperPage from "@routes/components/FormStepper"; import GridPage from "@routes/components/Grid"; import HeroBannerPage from "@routes/components/HeroBanner"; import IconsPage from "@routes/components/Icons"; -import IconButtonPage from '@routes/components/IconButton'; +import IconButtonPage from "@routes/components/IconButton"; import ListPage from "@routes/components/List"; import ModalPage from "@routes/components/Modal"; import NotificationBannerPage from "@routes/components/Notificationbanner"; -import PaginationPage from '@routes/components/Pagination'; +import PaginationPage from "@routes/components/Pagination"; import PopoverPage from "@routes/components/Popover"; import ProgressIndicatorPage from "@routes/components/ProgressIndicator"; import RadioPage from "@routes/components/Radio"; @@ -58,11 +58,10 @@ import TabsPage from "@routes/components/Tabs.tsx"; import TooltipPage from "@routes/components/Tooltip"; import TextFieldPage from "@routes/components/TextField"; import TextAreaPage from "@routes/components/TextArea"; -import MicrositeHeaderPage from '@routes/components/MicrositeHeader'; -import AppHeaderPage from '@routes/components/AppHeader'; -import AppFooterPage from '@routes/components/AppFooter'; -import SideMenuPage from '@routes/components/SideMenu'; - +import MicrositeHeaderPage from "@routes/components/MicrositeHeader"; +import AppHeaderPage from "@routes/components/AppHeader"; +import AppFooterPage from "@routes/components/AppFooter"; +import SideMenuPage from "@routes/components/SideMenu"; // Design Tokens @@ -87,8 +86,8 @@ import BugVerificationPage from "@routes/get-started/developers/BugVerification" import GetStartedLayout from "@routes/get-started/GetStartedLayout"; import GetStartedOverviewPage from "@routes/get-started/GetStartedOverview"; import QATestingOverviewPage from "@routes/get-started/qa-testing/QATestingOverview"; -import ContributePage from '@routes/get-started/Contribute'; -import SupportPage from '@routes/get-started/Support'; +import ContributePage from "@routes/get-started/Contribute"; +import SupportPage from "@routes/get-started/Support"; import RequestFeaturePage from "@routes/get-started/RequestFeature"; import ReportBugPage from "@routes/get-started/ReportBug"; import RoadmapPage from "@routes/get-started/Roadmap"; @@ -97,11 +96,11 @@ import UxDesignerPage from "@routes/get-started/designers/UxDesigner"; // Content Pages -import ContentLayout from '@routes/content/ContentLayout'; -import CapitalizationPage from '@routes/content/Capitalization'; -import DateFormatPage from '@routes/content/DateFormat'; -import ErrorMessagesPage from '@routes/content/ErrorMessages'; -import HelperTextPage from '@routes/content/HelperText'; +import ContentLayout from "@routes/content/ContentLayout"; +import CapitalizationPage from "@routes/content/Capitalization"; +import DateFormatPage from "@routes/content/DateFormat"; +import ErrorMessagesPage from "@routes/content/ErrorMessages"; +import HelperTextPage from "@routes/content/HelperText"; import UserExperienceGuidelinesPage from "@routes/get-started/UserExperienceGuidelines"; // Patterns Pages @@ -116,7 +115,6 @@ import QuestionPage from "@routes/patterns/QuestionPage"; import ReviewPage from "@routes/patterns/ReviewPage"; import ResultPage from "@routes/patterns/ResultPage"; - interface DeviceWidthProviderProps { children: ReactNode; } @@ -150,13 +148,13 @@ const router = createBrowserRouter( } /> } /> } /> - } /> } /> } /> } /> } /> } /> } /> + } /> } /> } /> } /> @@ -226,7 +224,6 @@ const router = createBrowserRouter( } /> - }> } /> @@ -238,13 +235,13 @@ const router = createBrowserRouter( } errorElement={}> } /> - } /> + } /> } /> - } /> - } /> - } /> - } /> - } /> + } /> + } /> + } /> + } /> + } /> ) diff --git a/src/routes/components/Accordion.tsx b/src/routes/components/Accordion.tsx index 99027e2f0..12bf9036d 100644 --- a/src/routes/components/Accordion.tsx +++ b/src/routes/components/Accordion.tsx @@ -156,6 +156,18 @@ export default function AccordionPage() { type: "none | 3xs | 2xs | xs | s | m | l | xl | 2xl | 3xl | 4xl", description: "Apply margin to the top, right, bottom, and/or left of the component.", }, + { + name: "_change", + lang: "angular", + type: "CustomEvent", + description: "Callback function when accordion heading is clicked.", + }, + { + name: "onChange", + lang: "react", + type: "(open: boolean) => void", + description: "Callback function when accordion heading is clicked.", + } ]; function onSandboxChange(bindings: ComponentBinding[], props: Record) { diff --git a/src/routes/components/AppFooter.tsx b/src/routes/components/AppFooter.tsx index 00586dc3b..4c16baa6d 100644 --- a/src/routes/components/AppFooter.tsx +++ b/src/routes/components/AppFooter.tsx @@ -160,7 +160,7 @@ export default function AppFooterPage() { Examples - + ({ - content: "Chip text", - }); - - const [componentBindings, setComponentBindings] = useState([ - { - label: "Leading icon", - type: "combobox", - name: "leadingIcon", - options: [""].concat(ICONS), - value: "", - }, - { - label: "Icon Theme", - type: "list", - name: "iconTheme", - options: ["", "outline", "filled"], - defaultValue: "outline", - value: "" - }, - { - label: "Deletable", - type: "boolean", - name: "deletable", - value: false, - }, - { - label: "Error", - type: "boolean", - name: "error", - value: false, - }, - { - label: "Content", - type: "string", - name: "content", - value: "Chip text", - }, - ]); - - const componentProperties: ComponentProperty[] = [ - { - name: "leadingicon", - type: "GoAIconType", - description: "Shows an icon to the left of the text.", - lang: "angular", - }, - { - name: "leadingIcon", - type: "GoAIconType", - description: "Shows an icon to the left of the text.", - lang: "react", - }, - { - name: "icontheme", - type: "outline | filled", - description: "The style of the leading icon", - defaultValue: "outline", - lang: "angular" - }, - { - name: "iconTheme", - type: "outline | filled", - description: "The style of the leading icon", - defaultValue: "outline", - lang: "react" - }, - { - name: "error", - type: "boolean", - description: "Shows an error state.", - }, - { - name: "deletable", - type: "boolean", - description: "Shows a delete icon button on the right of the text label.", - }, - { - name: "content", - type: "string", - required: true, - description: "Text label of the chip.", - }, - { - name: "_click", - type: "CustomEvent", - description: "Callback when deletable and delete icon is clicked.", - lang: "angular", - }, - { - name: "onClick", - type: "() = void", - description: "Callback when deletable and delete icon is clicked.", - lang: "react", - }, - { - name: "testId", - type: "string", - lang: "react", - description: "Sets the data-testid attribute. Used with ByTestId queries in tests.", - }, - { - name: "testid", - type: "string", - lang: "angular", - description: "Sets the data-testid attribute. Used with ByTestId queries in tests.", - }, - { - name: "mt,mr,mb,ml", - type: "none | 3xs | 2xs | xs | s | m | l | xl | 2xl | 3xl | 4xl", - description: "Apply margin to the top, right, bottom, and/or left of the component.", - }, - // ... - ]; - - function onSandboxChange(bindings: ComponentBinding[], props: Record) { - setComponentBindings(bindings); - setComponentProps(props as CastingType); - } - - return ( - <> - - - - - -

Component

- - - - -
- - - Design guidelines - - - } - > -
-
- - ); -} diff --git a/src/routes/components/Components.tsx b/src/routes/components/Components.tsx index dba7111d4..3af4caa30 100644 --- a/src/routes/components/Components.tsx +++ b/src/routes/components/Components.tsx @@ -38,13 +38,13 @@ export function Components() { Button group Callout Checkbox - Chip Container Date picker Details Divider Dropdown File uploader + Filter chip Footer Form item Form stepper diff --git a/src/routes/components/FilterChip.tsx b/src/routes/components/FilterChip.tsx new file mode 100644 index 000000000..7d3c93380 --- /dev/null +++ b/src/routes/components/FilterChip.tsx @@ -0,0 +1,520 @@ +import { Category, ComponentHeader } from "@components/component-header/ComponentHeader.tsx"; +import { + GoABadge, + GoAButton, + GoAButtonGroup, + GoAContainer, + GoAFilterChip, + GoAFilterChipProps, + GoAInput, + GoATab, + GoATabs, +} from "@abgov/react-components"; +import { ComponentBinding, LanguageContext, Sandbox } from "@components/sandbox"; +import { useContext, useState } from "react"; +import { + ComponentProperties, + ComponentProperty, +} from "@components/component-properties/ComponentProperties.tsx"; +import { ComponentContent } from "@components/component-content/ComponentContent"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; + +// Page props +const componentName = "Filter Chip"; +const description = "Allow the user to filter content."; +const category = Category.FEEDBACK_AND_ALERTS; +const relatedComponents = [ + { link: "/components/badge", name: "Badge" }, + { link: "/components/popover", name: "Popover" }, + { link: "/components/Table", name: "Table" }, +]; +type ComponentPropsType = GoAFilterChipProps; + +type CastingType = { + content: string; + [key: string]: unknown; +}; + +export default function FilterChipPage() { + const [componentProps, setComponentProps] = useState({ + content: "Chip text", + }); + const language = useContext(LanguageContext); + const [componentBindings, setComponentBindings] = useState([ + { + label: "Error", + type: "boolean", + name: "error", + value: false, + }, + { + label: "Content", + type: "string", + name: "content", + value: "Chip text", + }, + ]); + + const componentProperties: ComponentProperty[] = [ + { + name: "error", + type: "boolean", + description: "Shows an error state.", + }, + + { + name: "content", + type: "string", + required: true, + description: "Text label of the chip.", + }, + { + name: "_click", + type: "CustomEvent", + description: "Callback when deletable and delete icon is clicked.", + lang: "angular", + }, + { + name: "onClick", + type: "() = void", + description: "Callback when deletable and delete icon is clicked.", + lang: "react", + }, + { + name: "testId", + type: "string", + lang: "react", + description: "Sets the data-testid attribute. Used with ByTestId queries in tests.", + }, + { + name: "testid", + type: "string", + lang: "angular", + description: "Sets the data-testid attribute. Used with ByTestId queries in tests.", + }, + ]; + + function onSandboxChange(bindings: ComponentBinding[], props: Record) { + setComponentBindings(bindings); + setComponentProps(props as CastingType); + } + + const [chips, setChips] = useState(["Chip 1", "Chip 2", "Chip 3"]); + const [activeFilters, setActiveFilters] = useState([]); + + const deleteChip = (chip: string) => { + setChips(prevChips => prevChips.filter(c => c !== chip)); + }; + + const addFilter = () => { + const randomFilter = `Filter ${Math.floor(Math.random() * 100)}`; + if (!activeFilters.includes(randomFilter)) { + setActiveFilters(prevFilters => [...prevFilters, randomFilter]); + } + }; + + const removeFilter = (filter: string) => { + setActiveFilters(prevFilters => prevFilters.filter(f => f !== filter)); + }; + + const [typedChips, setTypedChips] = useState([ + "Typed Chip 1", + "Typed Chip 2", + "Typed Chip 3", + ]); + const [inputValue, setInputValue] = useState(""); + const handleInputChange = (_name: string, value: string) => { + setInputValue(value); + }; + + const handleInputKeyDown = (_name: string, value: string, key: string) => { + if (key === "Enter" && value.trim() !== "") { + setTypedChips(prevChips => [...prevChips, value.trim()]); + setTimeout(() => { + setInputValue(""); + }, 0); + } else if (key === "Backspace" && value === "" && typedChips.length > 0) { + setTypedChips(prevChips => prevChips.slice(0, -1)); + } + }; + + const removeTypedChip = (chip: string) => { + setTypedChips(prevChips => prevChips.filter(c => c !== chip)); + }; + + return ( + <> + + + + +

+ Component +

+ + + + + +

Delete Event

+ + {chips.map(chip => ( + deleteChip(chip)} mr="s" /> + ))} + + c !== chip); + } + `} + /> + + + + `} + /> + + { + setChips((prevChips) => prevChips.filter((c) => c !== chip)); + }; + `} + /> + + ( + deleteChip(chip)} + mr="s" + /> + ))} + `} + /> + + +

Interactive Example

+ + {activeFilters.map(filter => ( + removeFilter(filter)} + mr="s" + mb="s" + mt="s" + /> + ))} + + + Add Random Filter + + + f !== filter); + } + + addFilter(): void { + const randomFilter = "Filter " + Math.floor(Math.random() * 100); + if (!this.activeFilters.includes(randomFilter)) { + this.activeFilters.push(randomFilter); + } + } + `} + /> + + + + + + + Add Random Filter + + `} + /> + + ([]); + + const removeFilter = (filter: string) => { + setActiveFilters((prevFilters) => prevFilters.filter((f) => f !== filter)); + }; + + const addFilter = () => { + const randomFilter = 'Filter ' + Math.floor(Math.random() * 100); + if (!activeFilters.includes(randomFilter)) { + setActiveFilters(prevFilters => [...prevFilters, randomFilter]); + } + }; + `} + /> + + + {activeFilters.map((filter) => ( + removeFilter(filter)} + mr="s" + mb="s" + mt="s" + /> + ))} + + + Add Random Filter + + `} + /> + + +

Typed Chips Example

+ +
+ + {typedChips.map((chip, index) => ( + removeTypedChip(chip)} + mr="s" + mt="s" + mb="s" + /> + ))} +
+
+ + {language === "angular" && ( + <> + c !== chip); + } + + handleBackspace(event: KeyboardEvent): void { + if (!this.inputValue && this.typedChips.length > 0 && event.key === "Backspace") { + this.typedChips.pop(); + event.preventDefault(); + } + } + } + + `} + /> + + )} + + {language === "angular" && ( + <> + + + + + `} + /> + + )} + + {language === "react" && ( + <> + ([ + "Typed Chip 1", + "Typed Chip 2", + "Typed Chip 3", + ]); + const [inputValue, setInputValue] = useState(""); + const handleInputChange = (name: string, value: string) => { + setInputValue(value); + }; + + const handleInputKeyDown = (name: string, + value: string, + key: string) => { + if (key === "Enter" && value.trim() !== "") { + setTypedChips((prevChips) => [...prevChips, value.trim()]); + setTimeout(() => { + setInputValue(""); + }, 0); + } else if (key === "Backspace" + && value === "" + && typedChips.length > 0) { + setTypedChips((prevChips) => prevChips.slice(0, -1)); + } + }; + + const removeTypedChip = (chip: string) => { + setTypedChips((prevChips) => prevChips.filter((c) => c !== chip)); + }; + `} + /> + + + {typedChips.map((chip, index) => ( + removeTypedChip(chip)} + mr="s" + mt="s" + mb="s"/> + ))} + `} + /> + + )} +
+ + + Design guidelines + + + }> +
+
+ + ); +} diff --git a/src/routes/get-started/ReportBug.tsx b/src/routes/get-started/ReportBug.tsx index 38fc014ec..9e147efcf 100644 --- a/src/routes/get-started/ReportBug.tsx +++ b/src/routes/get-started/ReportBug.tsx @@ -10,13 +10,32 @@ import { GoATextArea } from "@abgov/react-components"; import { ComponentContent } from "@components/component-content/ComponentContent.tsx"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { Octokit } from "octokit"; import { useNavigate } from "react-router-dom"; export default function ReportBugPage() { + interface Package { + name: string; + location: string; + } + let navigate = useNavigate(); + const packages: Package[] = [ + { + name: "web", + location: "/@abgov/web-components" + }, + { + name: "angular", + location: "/@abgov/angular-components" + }, + { + name: "react", + location: "/@abgov/react-components" + } + ] const [formValues, setFormValues] = useState({ email: "", webVersion: "", @@ -28,6 +47,11 @@ export default function ReportBugPage() { jam: "", additional: "" }) + const [versions, setVersions] = useState({ + react: "", + angular: "", + web: "" + }) const [emailError, setEmailError] = useState(); const [webVersionError, setWebVersionError] = useState(); @@ -180,6 +204,26 @@ export default function ReportBugPage() { return valid; } + useEffect(() => { + async function getLatestVersion() { + for (let singlePackage of packages) { + try { + const response = await fetch("https://registry.npmjs.org" + singlePackage.location + "/latest"); + const data = await response.json(); + + setVersions(prevVersions => ({ + ...prevVersions, + [singlePackage.name]: data.version + })); + } catch (error) { + console.error("Error fetching version for ", singlePackage.name, error); + } + } + } + + getLatestVersion(); + }, []) + if (!formSubmitted) { return ( @@ -191,9 +235,9 @@ export default function ReportBugPage() {
    -
  • Web Components - 1.28.0
  • -
  • Angular Components - 3.2.0
  • -
  • React Components - 5.3.0
  • +
  • Web Components - { versions["web"] }
  • +
  • Angular Components - { versions["angular"] }
  • +
  • React Components - { versions["react"] }
diff --git a/src/routes/get-started/designers/UxDesigner.tsx b/src/routes/get-started/designers/UxDesigner.tsx index 4323f387b..6a0ac91d9 100644 --- a/src/routes/get-started/designers/UxDesigner.tsx +++ b/src/routes/get-started/designers/UxDesigner.tsx @@ -12,7 +12,7 @@ export default function UxDesignerPage() {

Overview

The design system provides designers with a library of{" "} - design tokens, + design tokens,{" "} components, and{" "} patterns in Figma that are also available to developers in code. @@ -35,8 +35,7 @@ export default function UxDesignerPage() { The design system tokens, styles, components and page templates are all available to pull into your file in Figma.

- -

Design system library - Figma

+ When selecting components, prioritize those with a “goa-” prefix in the name such as “goa-input.” These components are available in both design and development, which means that developers can avoid unnecessary custom development.

All - Simple form + Public form Pages diff --git a/src/routes/patterns/PatternsOverview.tsx b/src/routes/patterns/PatternsOverview.tsx index 27f4b7091..3fddddd76 100644 --- a/src/routes/patterns/PatternsOverview.tsx +++ b/src/routes/patterns/PatternsOverview.tsx @@ -13,7 +13,7 @@ export default function PatternsOverviewPage() {

Patterns

  • - Simple form + Public form
diff --git a/src/routes/patterns/SimpleFormPage.tsx b/src/routes/patterns/SimpleFormPage.tsx index 314425e95..e7c7881a6 100644 --- a/src/routes/patterns/SimpleFormPage.tsx +++ b/src/routes/patterns/SimpleFormPage.tsx @@ -6,12 +6,12 @@ import { Link } from "react-router-dom"; export default function SimpleFormPage() { return ( -

Simple form

+

Public form

Design forms that help Albertan citizens understand the task, focus on the question and its answer, and complete the form.

- +

Primary users: citizens, public, external
@@ -26,7 +26,7 @@ export default function SimpleFormPage() {

Form structure

- Use a simple form structure focused on content, and asking the right questions to your user + Use the public form structure focused on content, and asking the right questions to your user to keep the interaction as simple as possible.

@@ -131,7 +131,7 @@ export default function SimpleFormPage() {

Pages

simple form pages overview image