Button

Carry out an important action or navigate to another page.

Props

type
primary | submit | secondary | tertiary | start
Sets the visual style of the button. Use "primary" for main actions, "secondary" for alternative actions, "tertiary" for low-emphasis actions, and "start" for prominent call-to-action buttons.
Defaults to primary.
size
normal | compact
Controls the size of the button. Use "compact" for inline actions or space-constrained layouts.
Defaults to normal.
variant
normal | destructive | inverse
Sets the color variant for semantic meaning. Use "destructive" for delete or irreversible actions, "inverse" for dark backgrounds.
Defaults to normal.
disabled
boolean
When true, prevents user interaction and applies disabled styling.
Defaults to false.
leadingIcon
GoAIconType
Icon displayed before the button text.
trailingIcon
GoAIconType
Icon displayed after the button text.
testId
string
Sets a data-testid attribute for automated testing.
width
string
Sets a custom width for the button (e.g., "200px" or "100%").
version
1 | 2
Design system version. Version 2 includes updated styling and accessibility improvements.
Defaults to 2.
mt, mr, mb, ml
none | 3xs | 2xs | xs | s | m | l | xl | 2xl | 3xl | 4xl
Apply margin to the top, right, bottom, and/or left of the component.

Events

onClick
(event: Event) => void
_click
CustomEvent
Examples

Add a filter chip

ReactAngularWeb Components
const [activeFilters, setActiveFilters] = useState<string[]>([]);

  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));
  };
<div>
        {activeFilters.map((filter) => (
          <GoabFilterChip
            key={filter}
            content={filter}
            onClick={() => removeFilter(filter)}
            mr="s"
            mb="s"
            mt="s"
          />
        ))}
      </div>
      <GoabButton mt="l" onClick={addFilter}>Add Random Filter</GoabButton>

Add another item in a modal

ReactAngularWeb Components
const [open, setOpen] = useState(false);
  const [type, setType] = useState<string>();
  const [name, setName] = useState<string>();
  const [description, setDescription] = useState<string>();
<GoabButton type="tertiary" leadingIcon="add" onClick={() => setOpen(true)}>
        Add another item
      </GoabButton>
      <GoabModal
          heading="Add a new item"
          open={open}
          actions={
            <GoabButtonGroup alignment="end">
              <GoabButton type="tertiary" size="compact" onClick={() => setOpen(false)}>
                Cancel
              </GoabButton>
              <GoabButton type="primary" size="compact" onClick={() => setOpen(false)}>
                Save new item
              </GoabButton>
            </GoabButtonGroup>
          }
        >
          <p>Fill in the information to create a new item</p>
          <GoabFormItem label="Type" mt="l">
            <GoabDropdown onChange={(e) => setType(e.value)} value={type}>
              <GoabDropdownItem value="1" label="Option 1" />
              <GoabDropdownItem value="2" label="Option 2" />
            </GoabDropdown>
          </GoabFormItem>
          <GoabFormItem label="Name" mt="l">
            <GoabInput
              onChange={(e) => setName(e.value)}
              value={name}
              name="name"
              width="100%"
            />
          </GoabFormItem>
          <GoabFormItem label="Description" mt="l">
            <GoabTextarea
              name="description"
              rows={3}
              width="100%"
              onChange={(e) => setDescription(e.value)}
              value={description}
            />
          </GoabFormItem>
      </GoabModal>

Add a record using a drawer

ReactAngularWeb Components
const [open, setOpen] = useState(false);
<GoabButton leadingIcon="add" onClick={() => setOpen(true)}>
        Add Record
      </GoabButton>
      <GoabDrawer
        maxSize="492px"
        open={open}
        heading="Add Record"
        position="right"
        onClose={() => setOpen(false)}
        actions={
          <GoabButtonGroup>
            <GoabButton type="primary" size="compact" onClick={() => setOpen(false)}>
              Add record
            </GoabButton>
            <GoabButton type="tertiary" size="compact" onClick={() => setOpen(false)}>
              Cancel
            </GoabButton>
          </GoabButtonGroup>
        }
      >
        <GoabFormItem label="Level of education">
          <GoabDropdown onChange={() => {}} name="education" value="university">
            <GoabDropdownItem value="high-school" label="High School Diploma" />
            <GoabDropdownItem value="college" label="College Diploma" />
            <GoabDropdownItem value="university" label="University Degree" />
            <GoabDropdownItem value="masters" label="Master's Degree" />
            <GoabDropdownItem value="doctorate" label="Doctorate" />
          </GoabDropdown>
        </GoabFormItem>
        <GoabFormItem label="Educational institution" mt="l">
          <GoabInput name="education" type="text" onChange={() => {}} />
        </GoabFormItem>
        <GoabFormItem label="Field of study" requirement="optional" mt="l">
          <GoabInput name="fieldOfStudy" type="text" onChange={() => {}} />
        </GoabFormItem>
        <GoabFormItem label="Is the person currently attending?" mt="l">
          <GoabRadioGroup name="attendTraining" orientation="horizontal" onChange={() => {}}>
            <GoabRadioItem value="yes" label="Yes" />
            <GoabRadioItem value="no" label="No" />
          </GoabRadioGroup>
        </GoabFormItem>
        <GoabFormItem label="Start date" mt="l">
          <GoabDatePicker onChange={() => {}} value={new Date("2022-09-01")} />
          <GoabCheckbox name="startDateApproximate" text="Approximate date" value="y" mt="s" />
        </GoabFormItem>
        <GoabFormItem label="Credential received?" mt="l">
          <GoabRadioGroup name="credentialReceived" orientation="horizontal" onChange={() => {}}>
            <GoabRadioItem value="yes" label="Yes" />
            <GoabRadioItem value="no" label="No" />
          </GoabRadioGroup>
        </GoabFormItem>
      </GoabDrawer>

Add and edit lots of filters

ReactAngularWeb Components
const [open, setOpen] = useState(false);
<GoabButton onClick={() => setOpen(true)}>Filters</GoabButton>
      <GoabDrawer
          heading="Filters"
          open={open}
          onClose={() => setOpen(false)}
          position="right"
          actions={
            <GoabButtonGroup>
              <GoabButton type="primary" size="compact" onClick={() => setOpen(false)}>
                Apply filters
              </GoabButton>
              <GoabButton type="tertiary" size="compact" onClick={() => setOpen(false)}>
                Cancel
              </GoabButton>
            </GoabButtonGroup>
          }
        >
          <GoabFormItem label="Entry status">
            <GoabCheckboxList name="entryStatus" onChange={() => {}}>
              <GoabCheckbox name="draft" text="Draft" value="draft" />
              <GoabCheckbox name="published" text="Published" value="published" />
            </GoabCheckboxList>
          </GoabFormItem>
          <GoabFormItem label="Assigned to - Region" mt="l">
            <GoabCheckboxList name="region" onChange={() => {}}>
              <GoabCheckbox name="calgary" text="Calgary" value="calgary" />
              <GoabCheckbox name="central" text="Central" value="central" />
              <GoabCheckbox name="edmonton" text="Edmonton" value="edmonton" />
              <GoabCheckbox name="north" text="North" value="north" />
              <GoabCheckbox name="south" text="South" value="south" />
            </GoabCheckboxList>
          </GoabFormItem>
          <GoabFormItem label="Assigned to" mt="l">
            <GoabDropdown name="assignedTo" onChange={() => {}}>
              <GoabDropdownItem value="1" label="Person 1" />
              <GoabDropdownItem value="2" label="Person 2" />
            </GoabDropdown>
          </GoabFormItem>
          <GoabFormItem label="Date taken" mt="l">
            <GoabRadioGroup name="dateTaken" onChange={() => {}}>
              <GoabRadioItem value="24" label="Last 24 hours" />
              <GoabRadioItem value="72" label="Last 72 hours" />
            </GoabRadioGroup>
          </GoabFormItem>
      </GoabDrawer>

Ask a user for an address

ReactAngularWeb Components
const [address, setAddress] = useState("");
  const [suite, setSuite] = useState("");
  const [city, setCity] = useState("");
  const [province, setProvince] = useState("");
  const [postalCode, setPostalCode] = useState("");
<GoabText size="heading-l" mt="none" mb="xl">What is your address?</GoabText>
      <GoabFormItem label="Street Address">
        <GoabInput
          name="address"
          type="text"
          value={address}
          onChange={(e) => setAddress(e.value)}
          width="100%"
        />
      </GoabFormItem>
      <GoabFormItem label="Suite or unit #" mt="l">
        <GoabInput
          name="suite"
          type="text"
          value={suite}
          onChange={(e) => setSuite(e.value)}
          width="100%"
        />
      </GoabFormItem>
      <GoabFormItem label="City or town" mt="l">
        <GoabInput
          name="city"
          type="text"
          value={city}
          onChange={(e) => setCity(e.value)}
          width="100%"
        />
      </GoabFormItem>
      <GoabBlock direction="row" gap="l" mt="l">
        <GoabFormItem label="Province or territory">
          <GoabDropdown
            onChange={(e) => setProvince(e.value ?? "")}
            name="province"
            value={province}
          >
            <GoabDropdownItem label="Alberta" value="AB" />
            <GoabDropdownItem label="British Columbia" value="BC" />
            <GoabDropdownItem label="Manitoba" value="MB" />
            <GoabDropdownItem label="New Brunswick" value="NB" />
            <GoabDropdownItem label="Newfoundland and Labrador" value="NL" />
            <GoabDropdownItem label="Northwest Territories" value="NT" />
            <GoabDropdownItem label="Nova Scotia" value="NS" />
            <GoabDropdownItem label="Nunavut" value="NU" />
            <GoabDropdownItem label="Ontario" value="ON" />
            <GoabDropdownItem label="Prince Edward Island" value="PE" />
            <GoabDropdownItem label="Quebec" value="QC" />
            <GoabDropdownItem label="Saskatchewan" value="SK" />
            <GoabDropdownItem label="Yukon" value="YT" />
          </GoabDropdown>
        </GoabFormItem>
        <GoabFormItem label="Postal Code">
          <GoabInput
            name="postalCode"
            type="text"
            value={postalCode}
            onChange={(e) => setPostalCode(e.value)}
            width="7ch"
          />
        </GoabFormItem>
      </GoabBlock>
      <GoabButtonGroup alignment="start" mt="2xl">
        <GoabButton type="primary" onClick={() => {}}>
          Save and continue
        </GoabButton>
        <GoabButton type="secondary" onClick={() => {}}>
          Cancel
        </GoabButton>
      </GoabButtonGroup>

Ask a user one question at a time

ReactAngularWeb Components
<GoabLink leadingIcon="arrow-back" size="small">
        <a href="#">Back</a>
      </GoabLink>
      <GoabFormItem
        mt="xl"
        label="Are you currently in school?"
        labelSize="large"
        helpText="School includes foundational, skills and employment training, micro-credentials, post-secondary and continuing education.">
        <GoabRadioGroup name="school" ariaLabel="are you currently in school?" onChange={() => {}}>
          <GoabRadioItem value="yes" label="Yes" />
          <GoabRadioItem value="no" label="No" />
        </GoabRadioGroup>
      </GoabFormItem>
      <GoabButton type="submit" mt="2xl">
        Save and continue
      </GoabButton>

Button with Icon

ReactAngularWeb Components
<GoabButtonGroup>
      <GoabButton leadingIcon="arrow-back">Go back</GoabButton>
      <GoabButton trailingIcon="arrow-forward">Continue</GoabButton>
      <GoabButton type="secondary" leadingIcon="add">Add item</GoabButton>
    </GoabButtonGroup>

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.

Confirm a change

ReactAngularWeb Components
const [open, setOpen] = useState(false);
  const [effectiveDate, setEffectiveDate] = useState<Date | undefined>(new Date());

  const onChangeEffectiveDate = (detail: GoabDatePickerOnChangeDetail) => {
    setEffectiveDate(detail.value as Date);
  };
<GoabButton onClick={() => setOpen(true)}>Save and continue</GoabButton>

      <GoabModal
        heading="Address has changed"
        open={open}
        onClose={() => setOpen(false)}
        actions={
          <GoabButtonGroup alignment="end">
            <GoabButton type="secondary" size="compact" onClick={() => setOpen(false)}>
              Undo address change
            </GoabButton>
            <GoabButton type="primary" size="compact" onClick={() => setOpen(false)}>
              Confirm
            </GoabButton>
          </GoabButtonGroup>
        }>
        <GoabContainer type="non-interactive" accent="filled" padding="compact" width="full">
          <GoabText as="h4" mt="none" mb="s">Before</GoabText>
          <GoabText mt="none">123456 78 Ave NW, Edmonton, Alberta</GoabText>
          <GoabText as="h4" mt="none" mb="s">After</GoabText>
          <GoabText mt="none" mb="none">881 12 Ave NW, Edmonton, Alberta</GoabText>
        </GoabContainer>
        <GoabFormItem label="Effective date" mt="l">
          <GoabDatePicker
            onChange={onChangeEffectiveDate}
            name="effectiveDate"
            value={effectiveDate}
          />
        </GoabFormItem>
      </GoabModal>

Card view of case files

ReactAngularWeb Components
.case-file-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: var(--goa-space-m);
}
<GoabContainer mt="l">
        <div className="case-file-row">
          <GoabBlock direction="column" gap="2xs">
            <GoabText size="heading-xs" mt="none" mb="2xs">Fiscal year: 2021/2022</GoabText>
            <GoabText size="body-s" mt="none" mb="none">Submitted: April 23, 2023</GoabText>
          </GoabBlock>
          <GoabBlock direction="row" gap="l" alignment="center">
            <GoabBadge type="midtone" content="Not started" />
            <GoabButton type="tertiary" size="compact">Start</GoabButton>
          </GoabBlock>
        </div>
      </GoabContainer>

      <GoabContainer>
        <div className="case-file-row">
          <GoabBlock direction="column" gap="2xs">
            <GoabText size="heading-xs" mt="none" mb="2xs">Fiscal year: 2020/2021</GoabText>
            <GoabText size="body-s" mt="none" mb="none">Submitted: April 9, 2022</GoabText>
          </GoabBlock>
          <GoabBlock direction="row" gap="l" alignment="center">
            <GoabBadge type="important" content="Information needed" />
            <GoabButton type="tertiary" size="compact">Edit</GoabButton>
          </GoabBlock>
        </div>
      </GoabContainer>

      <GoabContainer>
        <div className="case-file-row">
          <GoabBlock direction="column" gap="2xs">
            <GoabText size="heading-xs" mt="none" mb="2xs">Fiscal year: 2019/2020</GoabText>
            <GoabText size="body-s" mt="none" mb="none">Submitted: April 14, 2021</GoabText>
          </GoabBlock>
          <GoabBlock direction="row" gap="l" alignment="center">
            <GoabBadge type="success" content="Approved" />
            <GoabButton type="tertiary" size="compact">View</GoabButton>
          </GoabBlock>
        </div>
      </GoabContainer>

Confirm a destructive action

ReactAngularWeb Components
const [open, setOpen] = useState(false);
<GoabButton
        type="tertiary"
        leadingIcon="trash"
        onClick={() => setOpen(true)}>
        Delete record
      </GoabButton>
      <GoabModal
        heading="Are you sure you want to delete this record?"
        open={open}
        onClose={() => setOpen(false)}
        actions={
          <GoabButtonGroup alignment="end">
            <GoabButton type="tertiary" size="compact" onClick={() => setOpen(false)}>
              Cancel
            </GoabButton>
            <GoabButton
              type="primary"
              variant="destructive"
              size="compact"
              onClick={() => setOpen(false)}>
              Delete record
            </GoabButton>
          </GoabButtonGroup>
        }>
        <p>This action cannot be undone.</p>
      </GoabModal>

Confirm before navigating away

ReactAngularWeb Components
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...");
  };
<GoabButton onClick={() => setOpen(true)}>Open</GoabButton>
      <GoabModal
        heading="Are you sure you want to change route?"
        open={open}
        onClose={() => setOpen(false)}
        actions={
          <GoabButtonGroup alignment="end">
            <GoabButton type="secondary" size="compact" onClick={() => setOpen(false)}>
              Cancel
            </GoabButton>
            <GoabButton type="primary" size="compact" onClick={handleChangeRoute}>
              Change route
            </GoabButton>
          </GoabButtonGroup>
        }
      />

Confirm that an application was submitted

ReactAngularWeb Components
<GoabText as="h1" mt="none">You have completed the application</GoabText>

      <GoabCallout type="success" heading="Your application was successful">
        <GoabText mt="none" mb="m">You will receive a copy of the confirmation to the email person@email.com</GoabText>
        <GoabText mt="none" mb="none">Confirmation number: <strong>1234ABC</strong></GoabText>
      </GoabCallout>

      <GoabText as="h2" mt="xl" mb="m">Go back to the dashboard, or direct your user somewhere else useful.</GoabText>
      <GoabText>
        Other information about what was just completed, other tertiary information, and/or contact information.
        <br />
        Phone: <a href="tel:7801234567">780 123 4567</a>
        <br />
        Email: <a href="mailto:information@gov.ab.ca">information@gov.ab.ca</a>
      </GoabText>

      <GoabButtonGroup alignment="start" mt="2xl">
        <GoabButton type="primary">Go to application</GoabButton>
        <GoabButton type="secondary">Back to dashboard</GoabButton>
      </GoabButtonGroup>

Disabled button with a required field

ReactAngularWeb Components
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("");
  };
<form>
      <GoabFormItem label="Name" requirement="required">
        <GoabInput
          name="input"
          type="text"
          onChange={handleInputChange}
          value={inputValue}
          width="100%"
        />
      </GoabFormItem>

      <GoabButtonGroup alignment="start" mt="xl">
        <GoabButton disabled={inputValue.trim() === ""} onClick={handleConfirm}>
          Confirm
        </GoabButton>
        <GoabButton type="secondary" onClick={handleCancel}>
          Cancel
        </GoabButton>
      </GoabButtonGroup>
    </form>

Display user information

ReactAngularWeb Components
const handleAddToCalendar = () => {
    console.log("Add to calendar clicked");
  };
<GoabContainer>
        <GoabText as="span" size="body-m" color="secondary" mt="none" mb="none">Housing Advisor</GoabText>
        <GoabText size="heading-m" mt="none" mb="s">Tracy Hero</GoabText>
        <GoabBlock direction="row" gap="s">
          <GoabBlock direction="column" gap="m">
            <GoabText as="span" size="heading-xs" mt="none" mb="none">Email</GoabText>
            <GoabText as="span" size="heading-xs" mt="none" mb="none">Phone</GoabText>
          </GoabBlock>
          <GoabBlock direction="column" gap="m">
            <GoabText as="span" size="body-m" mt="none" mb="none">tracyhero@email.com</GoabText>
            <GoabText as="span" size="body-m" mt="none" mb="none">283-203-4921</GoabText>
          </GoabBlock>
        </GoabBlock>
      </GoabContainer>

      <GoabContainer
        type="non-interactive"
        accent="thick"
        heading="Upcoming important due dates"
        actions={
          <GoabButton
            type="tertiary"
            size="compact"
            leadingIcon="calendar"
            onClick={handleAddToCalendar}>
            Add to calendar
          </GoabButton>
        }>
        <GoabTable width="100%" striped>
          <tbody>
            <tr>
              <td>Business plan submission</td>
              <td style={{ textAlign: "right" }}>June 30, 2024</td>
            </tr>
            <tr>
              <td>Annual review</td>
              <td style={{ textAlign: "right" }}>October 3, 2024</td>
            </tr>
            <tr>
              <td>Application submission</td>
              <td style={{ textAlign: "right" }}>December 20, 2024</td>
            </tr>
            <tr>
              <td>Application review</td>
              <td style={{ textAlign: "right" }}>January 3, 2025</td>
            </tr>
          </tbody>
        </GoabTable>
      </GoabContainer>

Dynamically add an item to a dropdown list

ReactAngularWeb Components
type Task = {
  value: string;
  label: string;
  mount: GoabDropdownItemMountType;
};

const DEFAULT_TASKS: Task[] = [
    { label: "Finish Report", value: "finish-report", mount: "append" },
    { label: "Attend Meeting", value: "attend-meeting", mount: "append" },
    { label: "Reply Emails", value: "reply-emails", mount: "append" },
  ];

  const [tasks, setTasks] = useState<Task[]>(DEFAULT_TASKS);
  const [newTask, setNewTask] = useState<string>("");
  const [mountType, setMountType] = useState<string>("append");
  const [selectedTask, setSelectedTask] = useState<string>("");
  const [taskError, setTaskError] = useState<boolean>(false);
  const [isReset, setIsReset] = useState<boolean>(false);

  function onMountTypeChange(value: string | undefined) {
    setMountType(value as string);
  }

  function addTask() {
    if (newTask === "") {
      setTaskError(true);
      return;
    }
    setTaskError(false);

    const task: Task = {
      label: newTask,
      value: newTask.toLowerCase().replace(" ", "-"),
      mount: mountType as GoabDropdownItemMountType,
    };
    setTasks([...tasks, task]);
    setNewTask("");
    setIsReset(false);
  }

  function reset() {
    setTasks(DEFAULT_TASKS);
    setMountType("append");
    setNewTask("");
    setSelectedTask("");
    setTaskError(false);
    setIsReset(true);
  }
<GoabFormItem
          requirement="required"
          label="Name of item"
          error={taskError ? "Please enter item name" : undefined}
          helpText="Add an item to the dropdown list below">
          <GoabInput
            onChange={(event: GoabInputOnChangeDetail) => setNewTask(event.value)}
            name="item"
            value={newTask}
          />
        </GoabFormItem>

        <GoabFormItem mt="l" label="Add to">
          <GoabRadioGroup
            name="mountType"
            onChange={(event: GoabRadioGroupOnChangeDetail) => onMountTypeChange(event.value)}
            value={mountType}
            orientation="horizontal">
            <GoabRadioItem value="prepend" label="Start" />
            <GoabRadioItem value="append" label="End" />
          </GoabRadioGroup>
        </GoabFormItem>

        <GoabButtonGroup alignment="start" gap="relaxed" mt="l">
          <GoabButton type="primary" onClick={addTask}>
            Add new item
          </GoabButton>
          <GoabButton type="tertiary" onClick={reset}>
            Reset list
          </GoabButton>
        </GoabButtonGroup>

        <GoabDivider mt="l" />

        <GoabFormItem mt="l" label="All items">
          <div style={{ width: isReset ? "320px" : "auto" }}>
            <GoabDropdown
              key={tasks.length}
              onChange={(event: GoabDropdownOnChangeDetail) =>
                setSelectedTask(event.value as string)
              }
              value={selectedTask}
              name="selectedTask">
              {tasks.map(task => (
                <GoabDropdownItem
                  key={task.value}
                  value={task.value}
                  mountType={task.mount}
                  label={task.label}
                />
              ))}
            </GoabDropdown>
          </div>
      </GoabFormItem>

Filter data in a table

ReactAngularWeb Components
const [typedChips, setTypedChips] = useState<string[]>([]);
  const [inputValue, setInputValue] = useState("");
  const [inputError, setInputError] = useState("");
  const errorEmpty = "Empty filter";
  const errorDuplicate = "Enter a unique filter";

  const data = useMemo(
    () => [
      {
        status: { type: "information" as GoabBadgeType, text: "In progress" },
        name: "Ivan Schmidt",
        id: "7838576954",
      },
      {
        status: { type: "success" as GoabBadgeType, text: "Completed" },
        name: "Luz Lakin",
        id: "8576953364",
      },
      {
        status: { type: "information" as GoabBadgeType, text: "In progress" },
        name: "Keith McGlynn",
        id: "9846041345",
      },
      {
        status: { type: "success" as GoabBadgeType, text: "Completed" },
        name: "Melody Frami",
        id: "7385256175",
      },
      {
        status: { type: "important" as GoabBadgeType, text: "Updated" },
        name: "Frederick Skiles",
        id: "5807570418",
      },
      {
        status: { type: "success" as GoabBadgeType, text: "Completed" },
        name: "Dana Pfannerstill",
        id: "5736306857",
      },
    ],
    []
  );

  const [dataFiltered, setDataFiltered] = useState(data);

  const handleInputChange = (detail: GoabInputOnChangeDetail) => {
    const newValue = detail.value.trim();
    setInputValue(newValue);
  };

  const handleInputKeyPress = (detail: GoabInputOnKeyPressDetail) => {
    if (detail.key === "Enter") {
      applyFilter();
    }
  };

  const applyFilter = () => {
    if (inputValue === "") {
      setInputError(errorEmpty);
      return;
    }
    if (typedChips.length > 0 && typedChips.includes(inputValue)) {
      setInputError(errorDuplicate);
      return;
    }
    setTypedChips([...typedChips, inputValue]);
    setTimeout(() => {
      setInputValue("");
    }, 0);
    setInputError("");
  };

  const removeTypedChip = (chip: string) => {
    setTypedChips(typedChips.filter(c => c !== chip));
    setInputError("");
  };

  const checkNested = useCallback((obj: object, chip: string): boolean => {
    return Object.values(obj).some(value =>
      typeof value === "object" && value !== null
        ? checkNested(value, chip)
        : typeof value === "string" && value.toLowerCase().includes(chip.toLowerCase())
    );
  }, []);

  const getFilteredData = useCallback(
    (typedChips: string[]) => {
      if (typedChips.length === 0) {
        return data;
      }
      return data.filter((item: object) =>
        typedChips.every(chip => checkNested(item, chip))
      );
    },
    [checkNested, data]
  );

  useEffect(() => {
    setDataFiltered(getFilteredData(typedChips));
  }, [getFilteredData, typedChips]);
<GoabFormItem id="filterChipInput" error={inputError} mb="m">
        <GoabBlock gap="xs" direction="row" alignment="start" width="100%">
          <div style={{ flex: 1 }}>
            <GoabInput
              name="filterChipInput"
              aria-labelledby="filterChipInput"
              value={inputValue}
              leadingIcon="search"
              width="100%"
              onChange={handleInputChange}
              onKeyPress={handleInputKeyPress}
            />
          </div>
          <GoabButton type="secondary" onClick={applyFilter} leadingIcon="filter">
            Filter
          </GoabButton>
        </GoabBlock>
      </GoabFormItem>

      {typedChips.length > 0 && (
        <div>
          <GoabText tag="span" color="secondary" mb="xs" mr="xs">
            Filter:
          </GoabText>
          {typedChips.map((typedChip, index) => (
            <GoabFilterChip
              key={index}
              content={typedChip}
              mb="xs"
              mr="xs"
              onClick={() => removeTypedChip(typedChip)}
            />
          ))}
          <GoabButton type="tertiary" size="compact" mb="xs" onClick={() => setTypedChips([])}>
            Clear all
          </GoabButton>
        </div>
      )}

      <GoabTable width="full">
        <thead>
          <tr>
            <th>Status</th>
            <th>Name</th>
            <th className="goa-table-number-header">ID Number</th>
          </tr>
        </thead>
        <tbody>
          {dataFiltered.map(item => (
            <tr key={item.id}>
              <td>
                <GoabBadge type={item.status.type} content={item.status.text} icon={false} />
              </td>
              <td>{item.name}</td>
              <td className="goa-table-number-column">{item.id}</td>
            </tr>
          ))}
        </tbody>
      </GoabTable>

      {dataFiltered.length === 0 && data.length > 0 && (
        <GoabBlock mt="l" mb="l">
          No results found
        </GoabBlock>
      )}

Form stepper with controlled navigation

ReactAngularWeb Components
const [step, setStep] = useState(1);

  function setPage(page: number) {
    if (page < 1 || page > 4) return;
    setStep(page);
  }
<GoabFormStepper step={step} onChange={(event: GoabFormStepperOnChangeDetail) => setStep(event.step)}>
        <GoabFormStep text="Personal details" />
        <GoabFormStep text="Employment history" />
        <GoabFormStep text="References" />
        <GoabFormStep text="Review" />
      </GoabFormStepper>

      <GoabPages current={step} mb="3xl" mt="xl" mr="xl" ml="xl">
        <div>
          <GoabSkeleton type="article" />
        </div>
        <div>
          <GoabSkeleton type="header" size="2" />
          <GoabSkeleton type="text" />
          <GoabSkeleton type="header" size="2" />
          <GoabSkeleton type="text" />
        </div>
        <div>
          <GoabSkeleton type="text" />
          <GoabSpacer vSpacing="m" />
          <GoabSkeleton type="text" />
        </div>
        <div>
          <GoabSkeleton type="header" size="2" />
          <GoabSkeleton type="text" />
          <GoabSpacer vSpacing="m" />
          <GoabSkeleton type="text" />
        </div>
      </GoabPages>

      <div style={{ display: "flex", justifyContent: "space-between" }}>
        <GoabButton type="secondary" onClick={() => setPage(step - 1)}>
          Previous
        </GoabButton>
        <GoabButton type="primary" onClick={() => setPage(step + 1)}>
          Next
        </GoabButton>
      </div>

Give background information before asking a question

ReactAngularWeb Components
const [selectedValue, setSelectedValue] = useState<string>("");

  const handleChange = (event: GoabRadioGroupOnChangeDetail) => {
    setSelectedValue(event.value as string);
  };

  const handleSubmit = () => {
    console.log("Selected:", selectedValue);
  };
<GoabLink leadingIcon="arrow-back" size="small" mb="none">
        Back
      </GoabLink>

      <GoabText as="h2" mt="xl" mb="m">Current school status</GoabText>
      <GoabText mt="none" mb="s">
        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.
      </GoabText>
      <GoabText mt="none" mb="s">
        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'.
      </GoabText>
      <GoabText mt="none" mb="xl">
        Contact your provider if you're concerned about your school status.
      </GoabText>

      <GoabFormItem label="Are you currently in school?">
        <GoabRadioGroup
          name="school"
          ariaLabel="are you currently in school?"
          onChange={handleChange}>
          <GoabRadioItem value="yes" label="Yes" />
          <GoabRadioItem value="no" label="No" />
        </GoabRadioGroup>
      </GoabFormItem>

      <GoabButton type="submit" mt="2xl" onClick={handleSubmit}>
        Save and continue
      </GoabButton>
  );
}

Give context before asking a long answer question

ReactAngularWeb Components
const [textValue, setTextValue] = useState("");

  const handleChange = (event: GoabTextareaOnChangeDetail) => {
    setTextValue(event.value);
  };

  const handleContinue = () => {
    console.log("Submitted:", textValue);
  };
<GoabLink leadingIcon="arrow-back" size="small" mb="none">
        Back
      </GoabLink>

      <GoabText as="h2" mt="xl" mb="m">Submit a question about your benefits</GoabText>
      <GoabText mt="none" mb="xl">
        If you need clarification about your benefit eligibility, payment schedule, or application status, submit your
        question here.
      </GoabText>

      <form>
        <GoabFormItem
          label="Provide details about your situation"
          helpText="Include specific details to help us answer your question quickly.">
          <GoabTextarea
            name="program"
            onChange={handleChange}
            value={textValue}
            maxCount={400}
            countBy="character"
          />
        </GoabFormItem>
      </form>

      <GoabDetails mt="m" heading="What kind of information is useful?">
        <p>
          Include your benefit program name, mention any recent correspondence you received and/or provide any
          relevant case or reference numbers.
        </p>
      </GoabDetails>

      <GoabButtonGroup alignment="start" mt="2xl">
        <GoabButton type="primary" onClick={handleContinue}>
          Continue
        </GoabButton>
      </GoabButtonGroup>
ReactAngularWeb Components
const [addressLine1, setAddressLine1] = useState("");
  const [addressLine2, setAddressLine2] = useState("");
  const [townCity, setTownCity] = useState("");
  const [province, setProvince] = useState("");
  const [postalCode, setPostalCode] = useState("");
<GoabLink leadingIcon="arrow-back" size="small" mb="none">
        Back
      </GoabLink>

      <GoabText as="h2" mt="xl" mb="m">Your address</GoabText>
      <GoabText mt="none" mb="xl">This is the home address of the person applying</GoabText>

      <GoabFormItem label="Address line 1">
        <GoabInput
          onChange={(event) => setAddressLine1(event.value)}
          value={addressLine1}
          name="address-line-1"
          ariaLabel="Address line 1"
          width="100%"
        />
      </GoabFormItem>

      <GoabFormItem label="Address line 2" mt="l">
        <GoabInput
          onChange={(event) => setAddressLine2(event.value)}
          value={addressLine2}
          name="address-line-2"
          ariaLabel="Address line 2"
          width="100%"
        />
      </GoabFormItem>

      <GoabFormItem label="Town or city" mt="l">
        <GoabInput
          onChange={(event) => setTownCity(event.value)}
          value={townCity}
          name="town-city"
          ariaLabel="Town or city name"
          width="460px"
        />
      </GoabFormItem>

      <GoabFormItem label="Province or territory" mt="l" id="provinceLabel">
        <GoabDropdown
          onChange={(event) => setProvince(event.value ?? "")}
          value={province}
          name="province-territory"
          ariaLabelledBy="provinceLabel"
        >
          <GoabDropdownItem value="AB" label="Alberta" />
          <GoabDropdownItem value="BC" label="British Columbia" />
          <GoabDropdownItem value="MB" label="Manitoba" />
          <GoabDropdownItem value="NB" label="New Brunswick" />
          <GoabDropdownItem value="NL" label="Newfoundland and Labrador" />
          <GoabDropdownItem value="NS" label="Nova Scotia" />
          <GoabDropdownItem value="ON" label="Ontario" />
          <GoabDropdownItem value="PE" label="Prince Edward Island" />
          <GoabDropdownItem value="QC" label="Quebec" />
          <GoabDropdownItem value="SK" label="Saskatchewan" />
          <GoabDropdownItem value="NT" label="Northwest Territories" />
          <GoabDropdownItem value="NU" label="Nunavut" />
          <GoabDropdownItem value="YT" label="Yukon" />
        </GoabDropdown>
      </GoabFormItem>

      <GoabFormItem label="Postal code" mt="l">
        <GoabInput
          onChange={(event) => setPostalCode(event.value)}
          value={postalCode}
          name="postal-code"
          width="105px"
        />
      </GoabFormItem>

      <GoabButton type="submit" mt="2xl">
        Save and continue
      </GoabButton>

Hero banner with actions

ReactAngularWeb Components
function handleClick() {
    console.log("Call to action clicked");
  }
<GoabHeroBanner heading="Supporting Businesses">
      Resources are available to help Alberta entrepreneurs and small businesses
      start, grow and succeed.
      <GoabHeroBannerActions>
        <GoabButton type="start" onClick={handleClick}>
          Call to action
        </GoabButton>
      </GoabHeroBannerActions>
    </GoabHeroBanner>

Hide and show many sections of information

ReactAngularWeb Components
const [expandedAll, setExpandedAll] = useState<boolean>(false);
  const [expandedList, setExpandedList] = useState<number[]>([]);

  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);
    });
  };
<GoabButton type="tertiary" size="compact" mb="m" onClick={() => expandOrCollapseAll()}>
        {expandedAll ? "Hide all sections" : "Show all sections"}
      </GoabButton>

      <GoabAccordion
        open={expandedList.includes(1)}
        heading="How do I create an account?"
        headingSize="medium"
        onChange={(open) => updateAccordion(1, open)}
      >
        To create an account you will need to contact your office admin.
      </GoabAccordion>

      <GoabAccordion
        open={expandedList.includes(2)}
        heading="What verification is needed to sign documents digitally?"
        headingSize="medium"
        onChange={(open) => updateAccordion(2, open)}
      >
        You will need to verify your identity through our two factor
        authentication in addition to the digital signature.
      </GoabAccordion>

      <GoabAccordion
        open={expandedList.includes(3)}
        heading="Can I track the status of my service requests online?"
        headingSize="medium"
        onChange={(open) => 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.
      </GoabAccordion>

      <GoabAccordion
        open={expandedList.includes(4)}
        heading="Are there accessibility features for people with disabilities?"
        headingSize="medium"
        onChange={(open) => updateAccordion(4, open)}
      >
        Yes, our digital service is designed with accessibility in mind.{" "}
        <a href="#">More information on accessibility.</a>
      </GoabAccordion>

Question page

ReactAngularWeb Components
const [answer, setAnswer] = useState("");

  const handleContinue = () => {
    console.log("Answer submitted:", answer);
  };
<GoabLink leadingIcon="arrow-back" size="small" mb="none">
        Back
      </GoabLink>

      <GoabText as="h1" mt="xl" mb="m">What is your email address?</GoabText>
      <GoabText mt="none" mb="xl">We'll use this to send you confirmation of your application.</GoabText>

      <GoabFormItem label="Email address">
        <GoabInput
          name="email"
          type="email"
          value={answer}
          onChange={(e) => setAnswer(e.value)}
          width="100%"
        />
      </GoabFormItem>

      <GoabButtonGroup alignment="start" mt="2xl">
        <GoabButton type="primary" onClick={handleContinue}>
          Continue
        </GoabButton>
      </GoabButtonGroup>
  );
}

Reset date picker field

ReactAngularWeb Components
const [date, setDate] = useState<Date | undefined>();

  const setNewDate = (value: Date | undefined) => {
    setDate(value);
  };

  function setValue() {
    const d = new Date();
    d.setDate(d.getDate() - 7);
    setDate(d);
  }

  function clearValue() {
    setDate(undefined);
  }
<GoabFormItem label="Date Picker">
        <GoabDatePicker
          name="item"
          value={date}
          onChange={(e) => setNewDate(e.value as Date)}
          mb="xl"
        />
      </GoabFormItem>

      <GoabButtonGroup mt="xs" alignment="start">
        <GoabButton onClick={setValue}>
          Set Value
        </GoabButton>
        <GoabButton onClick={clearValue}>Clear Value</GoabButton>
      </GoabButtonGroup>

Require user action before continuing

ReactAngularWeb Components
const [open, setOpen] = useState(false);
<GoabButton onClick={() => setOpen(true)}>Open Basic Modal</GoabButton>
      <GoabModal
        heading="Are you sure you want to continue?"
        open={open}
        onClose={() => setOpen(false)}
        actions={
          <GoabButtonGroup alignment="end">
            <GoabButton type="secondary" size="compact" onClick={() => setOpen(false)}>
              Back
            </GoabButton>
            <GoabButton type="primary" size="compact" onClick={() => setOpen(false)}>
              Continue
            </GoabButton>
          </GoabButtonGroup>
        }
      >
        <p>You cannot return to this page.</p>
      </GoabModal>

Review and action

ReactAngularWeb Components
<GoabGrid minChildWidth="315px">
      <GoabContainer accent="thin" type="non-interactive">
        <GoabText size="heading-m" mt="none" mb="m">Appearance details</GoabText>
        <GoabGrid minChildWidth="200px" gap="m">
          <GoabBlock direction="column" gap="xs">
            <GoabText size="body-s" color="secondary" mt="none" mb="none">Accused name</GoabText>
            <GoabText size="body-m" mt="none" mb="none">Doe, John Scott</GoabText>
          </GoabBlock>

          <GoabBlock direction="column" gap="xs">
            <GoabText size="body-s" color="secondary" mt="none" mb="none">Date of birth</GoabText>
            <GoabText size="body-m" mt="none" mb="none">Mar 14, 2021</GoabText>
          </GoabBlock>

          <GoabBlock direction="column" gap="xs">
            <GoabText size="body-s" color="secondary" mt="none" mb="none">Court location</GoabText>
            <GoabText size="body-m" mt="none" mb="none">Calgary</GoabText>
          </GoabBlock>

          <GoabBlock direction="column" gap="xs">
            <GoabText size="body-s" color="secondary" mt="none" mb="none">Upcoming appearance date(s)</GoabText>
            <GoabText size="body-m" mt="none" mb="none">Sep 20, 2021</GoabText>
          </GoabBlock>
        </GoabGrid>

        <GoabText size="heading-xs" mt="l" mb="s">Docket number(s) &amp; charges</GoabText>
        <GoabContainer type="non-interactive" padding="compact">
          <GoabText size="heading-xs" mt="none" mb="xs">1

Review page

ReactAngularWeb Components
<GoabText size="heading-l" mt="none" mb="none">Review your answers</GoabText>
      <GoabText size="heading-s" color="secondary" mt="l" mb="none">Your situation</GoabText>
      <GoabTable mt="l">
        <tbody>
          <tr>
            <td>
              <strong>What was your (the applicant's) relationship to the deceased?</strong>
            </td>
            <td>Other</td>
            <td>
              <GoabLink>Change</GoabLink>
            </td>
          </tr>
          <tr>
            <td>
              <strong>My relationship to the deceased was</strong>
            </td>
            <td>Manager</td>
            <td>
              <GoabLink>Change</GoabLink>
            </td>
          </tr>
          <tr>
            <td>
              <strong>
                Was the deceased part of a household that was receiving Assured Income for the
                Severely Handicapped (AISH) or Income Support?
              </strong>
            </td>
            <td>No</td>
            <td>
              <GoabLink>Change</GoabLink>
            </td>
          </tr>
          <tr>
            <td>
              <strong>Was the deceased a minor?</strong>
            </td>
            <td>No</td>
            <td>
              <GoabLink>Change</GoabLink>
            </td>
          </tr>
          <tr>
            <td>
              <strong>What was the deceased's marital status at time of death?</strong>
            </td>
            <td>Married</td>
            <td>
              <GoabLink>Change</GoabLink>
            </td>
          </tr>
          <tr>
            <td>
              <strong>Did the deceased have any dependents?</strong>
            </td>
            <td>No</td>
            <td>
              <GoabLink>Change</GoabLink>
            </td>
          </tr>
          <tr>
            <td>
              <strong>Was the deceased a sponsored immigrant?</strong>
            </td>
            <td>Yes</td>
            <td>
              <GoabLink>Change</GoabLink>
            </td>
          </tr>
        </tbody>
      </GoabTable>
      <GoabButtonGroup alignment="start" mt="2xl">
        <GoabButton type="primary">Confirm and continue</GoabButton>
        <GoabButton type="tertiary">Back to application overview</GoabButton>
      </GoabButtonGroup>
  );
}
ReactAngularWeb Components
const [search, setSearch] = useState("");

  const onClick = () => {
    console.log("search:", search);
  };
<form>
      <GoabFormItem>
        <GoabBlock gap="xs" direction="row">
          <GoabInput
            type="search"
            name="search"
            value={search}
            onChange={(e) => setSearch(e.value)}
            leadingIcon="search"
          />
          <GoabButton type="primary" onClick={onClick}>
            Search
          </GoabButton>
        </GoabBlock>
      </GoabFormItem>
    </form>

Set a specific tab to be active

ReactAngularWeb Components
const review = [0, 1, 2, 3];
  const complete = [0, 1];
<GoabTabs initialTab={2}>
      <GoabTab heading="All">
        <GoabTable width="100%">
          <thead>
            <tr>
              <th>Status</th>
              <th>Text</th>
              <th className="goa-table-number-header">Number</th>
              <th style={{ width: "1%", whiteSpace: "nowrap" }}>Action</th>
            </tr>
          </thead>
          <tbody>
            {review.map((i) => (
              <tr key={`review-${i}`}>
                <td>
                  <GoabBadge type="important" content="Review pending" />
                </td>
                <td>Lorem Ipsum</td>
                <td className="goa-table-number-column">1234567890</td>
                <td>
                  <GoabButton type="tertiary" size="compact">Action</GoabButton>
                </td>
              </tr>
            ))}
            {complete.map((i) => (
              <tr key={`complete-${i}`}>
                <td>
                  <GoabBadge type="information" content="Complete" />
                </td>
                <td>Lorem Ipsum</td>
                <td className="goa-table-number-column">1234567890</td>
                <td>
                  <GoabButton type="tertiary" size="compact">Action</GoabButton>
                </td>
              </tr>
            ))}
          </tbody>
        </GoabTable>
      </GoabTab>
      <GoabTab heading={<>Review pending<GoabBadge type="important" content="4" icon={false} /></>}>
        <GoabTable width="100%">
          <thead>
            <tr>
              <th>Status</th>
              <th>Text</th>
              <th className="goa-table-number-header">Number</th>
              <th style={{ width: "1%", whiteSpace: "nowrap" }}>Action</th>
            </tr>
          </thead>
          <tbody>
            {review.map((i) => (
              <tr key={i}>
                <td>
                  <GoabBadge type="important" content="Review pending" />
                </td>
                <td>Lorem Ipsum</td>
                <td className="goa-table-number-column">1234567890</td>
                <td>
                  <GoabButton type="tertiary" size="compact">Action</GoabButton>
                </td>
              </tr>
            ))}
          </tbody>
        </GoabTable>
      </GoabTab>
      <GoabTab heading={<>Complete<GoabBadge type="information" content="338" icon={false} /></>}>
        <GoabTable width="100%">
          <thead>
            <tr>
              <th>Status</th>
              <th>Text</th>
              <th className="goa-table-number-header">Number</th>
              <th style={{ width: "1%", whiteSpace: "nowrap" }}>Action</th>
            </tr>
          </thead>
          <tbody>
            {complete.map((i) => (
              <tr key={i}>
                <td>
                  <GoabBadge type="information" content="Complete" />
                </td>
                <td>Lorem Ipsum</td>
                <td className="goa-table-number-column">1234567890</td>
                <td>
                  <GoabButton type="tertiary" size="compact">Action</GoabButton>
                </td>
              </tr>
            ))}
          </tbody>
        </GoabTable>
      </GoabTab>
    </GoabTabs>

Set the status of step on a form stepper

ReactAngularWeb Components
const [step, setStep] = useState<number>(-1);
  const status: GoabFormStepStatus[] = [
    "complete",
    "complete",
    "incomplete",
    "not-started"
  ];

  function setPage(page: number) {
    if (page < 1 || page > 4) return;
    setStep(page);
  }
<GoabFormStepper step={step} onChange={(event) => setStep(event.step)}>
        <GoabFormStep text="Personal details" status={status[0]} />
        <GoabFormStep text="Employment history" status={status[1]} />
        <GoabFormStep text="References" status={status[2]} />
        <GoabFormStep text="Review" status={status[3]} />
      </GoabFormStepper>
      <GoabPages current={step} mb="3xl" mt="xl" mr="xl" ml="xl">
        <div>
          <GoabSkeleton type="article" />
        </div>
        <div>
          <GoabSkeleton type="header" size="2" />
          <GoabSkeleton type="text" />
          <GoabSkeleton type="header" size="2" />
          <GoabSkeleton type="text" />
        </div>
        <div>
          <GoabSkeleton type="text" />
          <GoabSpacer vSpacing="m" />
          <GoabSkeleton type="text" />
        </div>
        <div>
          <GoabSkeleton type="header" size="2" />
          <GoabSkeleton type="text" />
          <GoabSpacer vSpacing="m" />
          <GoabSkeleton type="text" />
        </div>
      </GoabPages>
      <div style={{ display: "flex", justifyContent: "space-between" }}>
        <GoabButton type="secondary" onClick={() => setPage(step - 1)}>
          Previous
        </GoabButton>
        <GoabButton type="primary" onClick={() => setPage(step + 1)}>
          Next
        </GoabButton>
      </div>

Show a notification

ReactAngularWeb Components
const save = async () => {
    // await api.save();

    TemporaryNotification.show("Your application has been saved.", {
      type: "success"
    });
  };
<GoabTemporaryNotificationCtrl />
      <GoabButton type="secondary" onClick={save}>Save</GoabButton>

Show a notification with an action

ReactAngularWeb Components
const comment = () => {
    const uuid = TemporaryNotification.show(
      "Edna Mode commented on your assigned case.",
      {
        actionText: "View",
        action: () => {
          TemporaryNotification.dismiss(uuid);
        }
      }
    );
  };
<GoabTemporaryNotificationCtrl />
      <GoabButton onClick={comment}>Comment</GoabButton>

Show a section title on a question page

ReactAngularWeb Components
<GoabLink leadingIcon="arrow-back" size="small" mb="none">
        Back
      </GoabLink>

      <GoabText as="h3" size="body-m" mt="xl" mb="m" color="secondary">Personal information</GoabText>

      <GoabFormItem label="Do you currently live in Canada?" labelSize="large">
        <GoabRadioGroup
          name="canada"
          ariaLabel="Do you currently live in Canada?"
          onChange={() => {}}>
          <GoabRadioItem value="yes" label="Yes" />
          <GoabRadioItem value="no" label="No" />
        </GoabRadioGroup>
      </GoabFormItem>

      <GoabButton type="submit" mt="2xl">
        Save and continue
      </GoabButton>

Show a simple progress indicator on a question page

ReactAngularWeb Components
<GoabLink leadingIcon="arrow-back" size="small" mb="none">
        Back
      </GoabLink>

      <GoabText as="h3" size="body-m" mt="xl" mb="m" color="secondary">Question 3 of 9</GoabText>

      <GoabFormItem label="Do you currently live in Canada?" labelSize="large">
        <GoabRadioGroup
          name="canada"
          ariaLabel="Do you currently live in Canada?"
          onChange={() => {}}>
          <GoabRadioItem value="yes" label="Yes" />
          <GoabRadioItem value="no" label="No" />
        </GoabRadioGroup>
      </GoabFormItem>

      <GoabButton type="submit" mt="2xl">
        Save and continue
      </GoabButton>

Show a simple progress indicator on a question page with multiple questions

ReactAngularWeb Components
<GoabLink leadingIcon="arrow-back" size="small" mb="none">
        Back
      </GoabLink>

      <GoabText as="h3" size="body-m" mt="xl" mb="none" color="secondary">Step 1 of 5</GoabText>
      <GoabText as="h2" mt="xs" mb="xl">Personal information</GoabText>

      <GoabFormItem label="What is your name?">
        <GoabInput onChange={() => {}} name="name" ariaLabel="what is your name?" width="50ch" />
      </GoabFormItem>

      <GoabFormItem label="What is your phone number?" mt="l">
        <GoabInput
          onChange={() => {}}
          name="phone-number"
          ariaLabel="what is your phone number?"
          leadingContent="+1"
        />
      </GoabFormItem>

      <GoabFormItem label="What is your home postal code?" mt="l">
        <GoabInput
          onChange={() => {}}
          name="postal-code"
          width="14ch"
          ariaLabel="what is your home postal code"
        />
      </GoabFormItem>

      <GoabButton type="submit" mt="2xl">
        Save and continue
      </GoabButton>

Show a user progress

ReactAngularWeb Components
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);
      }
    });
  };
<GoabTemporaryNotificationCtrl />
      <GoabButton type="tertiary" leadingIcon="download" onClick={downloadReport}>
        Download report
      </GoabButton>

Show a user progress when the time is unknown

ReactAngularWeb Components
const searchCMS = async (): Promise<Error | undefined> => {
    // 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,
      });
    }
  };
<GoabTemporaryNotificationCtrl />
      <GoabButton type="secondary" leadingIcon="search" onClick={search}>
        Search case history
      </GoabButton>

Show different views of data in a table

ReactAngularWeb Components
const review = [0, 1, 2, 3];
  const complete = [0, 1];
<GoabTabs initialTab={1}>
          <GoabTab heading="All">
            <GoabTable width="100%">
              <thead>
                <tr>
                  <th>Status</th>
                  <th>Text</th>
                  <th className="goa-table-number-header">Number</th>
                  <th style={{ width: "1%", whiteSpace: "nowrap" }}>Action</th>
                </tr>
              </thead>
              <tbody>
                {review.map((i) => (
                  <tr key={`review-${i}`}>
                    <td>
                      <GoabBadge type="important" content="Review pending" />
                    </td>
                    <td>Lorem Ipsum</td>
                    <td className="goa-table-number-column">1234567890</td>
                    <td>
                      <GoabButton type="tertiary" size="compact">Action</GoabButton>
                    </td>
                  </tr>
                ))}
                {complete.map((i) => (
                  <tr key={`complete-${i}`}>
                    <td>
                      <GoabBadge type="information" content="Complete" />
                    </td>
                    <td>Lorem Ipsum</td>
                    <td className="goa-table-number-column">1234567890</td>
                    <td>
                      <GoabButton type="tertiary" size="compact">Action</GoabButton>
                    </td>
                  </tr>
                ))}
              </tbody>
            </GoabTable>
          </GoabTab>
          <GoabTab
            heading={
                Review pending
                <GoabBadge type="important" content="4" icon={false} />
            }
          >
            <GoabTable width="100%">
              <thead>
                <tr>
                  <th>Status</th>
                  <th>Text</th>
                  <th className="goa-table-number-header">Number</th>
                  <th style={{ width: "1%", whiteSpace: "nowrap" }}>Action</th>
                </tr>
              </thead>
              <tbody>
                {review.map((i) => (
                  <tr key={i}>
                    <td>
                      <GoabBadge type="important" content="Review pending" />
                    </td>
                    <td>Lorem Ipsum</td>
                    <td className="goa-table-number-column">1234567890</td>
                    <td>
                      <GoabButton type="tertiary" size="compact">Action</GoabButton>
                    </td>
                  </tr>
                ))}
              </tbody>
            </GoabTable>
          </GoabTab>
          <GoabTab
            heading={
              <>
                Complete
                <GoabBadge type="information" content="338" icon={false} />
              </>
            }
          >
            <GoabTable width="100%">
              <thead>
                <tr>
                  <th>Status</th>
                  <th>Text</th>
                  <th className="goa-table-number-header">Number</th>
                  <th style={{ width: "1%", whiteSpace: "nowrap" }}>Action</th>
                </tr>
              </thead>
              <tbody>
                {complete.map((i) => (
                  <tr key={i}>
                    <td>
                      <GoabBadge type="information" content="Complete" />
                    </td>
                    <td>Lorem Ipsum</td>
                    <td className="goa-table-number-column">1234567890</td>
                    <td>
                      <GoabButton type="tertiary" size="compact">Action</GoabButton>
                    </td>
                  </tr>
                ))}
              </tbody>
            </GoabTable>
          </GoabTab>
    </GoabTabs>

Show more information to help answer a question

ReactAngularWeb Components
<GoabLink leadingIcon="arrow-back" size="small" mb="none">
        Back
      </GoabLink>

      <GoabFormItem
        mt="xl"
        label="Do you pay for child care?"
        labelSize="large"
        helpText="Examples of child care are daycares, day homes and baby-sisters."
      >
        <GoabRadioGroup
          name="child-care"
          ariaLabel="Do you pay for child care?"
          onChange={() => {}}
        >
          <GoabRadioItem value="yes" label="Yes" />
          <GoabRadioItem value="no" label="No" />
        </GoabRadioGroup>
      </GoabFormItem>

      <GoabDetails heading="Why are we asking this question?" mt="l">
        <p>We ask this question to determine if you are eligible for child care benefits.</p>
      </GoabDetails>

      <GoabButton type="submit" mt="2xl">
        Save and continue
      </GoabButton>

Show status in a table

ReactAngularWeb Components
interface BadgeValue {
  key: number;
  type: GoabBadgeType;
  content: string;
}

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");
  };
<GoabTable width="100%">
      <thead>
        <tr>
          <th>Status</th>
          <th>Name</th>
          <th className="goa-table-number-header">File number</th>
          <th style={{ width: "1%", whiteSpace: "nowrap" }}></th>
        </tr>
      </thead>
      <tbody>
        {badgeValues.map((badge) => (
          <tr key={badge.key}>
            <td>
              <GoabBadge type={badge.type} content={badge.content} icon={false} />
            </td>
            <td>Lorem ipsum dolor sit amet consectetur</td>
            <td className="goa-table-number-column">1234567890</td>
            <td>
              <GoabButton size="compact" type="tertiary" onClick={handleClick}>
                Assign
              </GoabButton>
            </td>
          </tr>
        ))}
      </tbody>
    </GoabTable>

Start page

ReactAngularWeb Components
const handleClick = () => {
    console.log("Get started clicked");
  };
<GoabText size="heading-xl" mt="none" mb="l">Name of service</GoabText>
      <GoabText size="body-l" mt="none" mb="none">
        A short overview of the service. This is a couple sentences that helps the user understand
        what the service is.
      </GoabText>
      <GoabText size="body-m" mt="l" mb="s">Use this service to apply for [service]. You can use this service to:</GoabText>
      <ul>
        <li>see if you or a family member is eligible for [service]</li>
        <li>create and submit an application for [service]</li>
        <li>continue an application for [service] that you already started</li>
      </ul>

      <GoabText size="heading-l" mt="xl" mb="none">Before you begin</GoabText>
      <GoabText size="body-m" mt="l" mb="none">The application form should take about 20 minutes to complete.</GoabText>
      <GoabText size="body-m" mt="l" mb="none">
        <strong>In order to complete the application you will need:</strong>
      </GoabText>
      <ul>
        <li>government issued ID for the person applying</li>
      </ul>
      <GoabButton mt="2xl" mb="xl" type="start" onClick={handleClick}>
        Get started
      </GoabButton>

      <GoabText size="heading-l" mt="xl" mb="none">Other information about the service</GoabText>
      <GoabText size="body-m" mt="l" mb="none">
        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.
      </GoabText>

      <GoabText size="heading-l" mt="xl" mb="none">Support</GoabText>
      <GoabText size="body-m" mt="l" mb="none">
        For assistance, email us at <a href="mailto:help@gov.ab.ca">help@gov.ab.ca</a>
      </GoabText>

Warn a user of a deadline

ReactAngularWeb Components
const [open, setOpen] = useState(false);
<GoabButton type="secondary" onClick={() => setOpen(true)}>
        Save for later
      </GoabButton>
      <GoabModal
        heading="Complete submission prior to 1PM"
        calloutVariant="important"
        open={open}
        onClose={() => setOpen(false)}
        actions={
          <GoabButtonGroup alignment="end">
            <GoabButton type="primary" onClick={() => setOpen(false)}>
              I understand
            </GoabButton>
          </GoabButtonGroup>
        }
      >
        <p>
          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.
        </p>
      </GoabModal>
  );
}

States

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.

Avoid using disabled buttons. They have poor contrast and can confuse users.

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.

Keep buttons enabled and use error handling to provide clear feedback when the user submits.
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
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.

Content

SubmitCancel
Use one word to explain the function whenever possible, such as "Save", "Submit", or "Search".
Cancel application
Use descriptive language in both modal content and button text to inform users of the resulting destructive action.
SUBMITcancel
Don't use all uppercase or all lowercase to label buttons.
Submit applicationSave draftCancel
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".

Sizing

Edit
Use compact buttons in dense spaces like tables or container title bars.
CancelSave
Don't stack standard and full width buttons.
SaveCancel
Don't use different button sizes in the same area to emphasize hierarchy.
SaveCancel
Use full width buttons on mobile.

Types

  • 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.
Delete account
Use the destructive button variant for actions that cannot be easily undone, like permanently deleting data or removing a user from a system.
Delete record
Don't use a destructive button to trigger a confirmation. Reserve destructive styling for the final action inside the modal.
SaveSubmitContinue
Avoid using more than one primary button per page. Multiple primary buttons create visual competition and make it unclear which action is most important.
SaveCancel
Use a primary button for main actions and a secondary button for less important actions.
Submit form

This distinction matters for screen reader users who expect different behaviors, keyboard navigation patterns, and browser history.

Use a button for actions that trigger functionality (submit, save, cancel). Use a link for navigation to different pages or external websites.
Go to homepage
Don't use Button for simple navigation (use Link), toggling state (use Toggle or Checkbox), or minor utility functions (use Icon Button).
Submit application
Use a button when you need users to take a specific action, such as submitting a form, starting a process, or confirming a decision.

Icons

Add item
Use icons with a clear visual association to the action.
Confirm
Don't use icons that don't have a clear visual association to the intended outcome.
Add new
Use a text label with an icon, especially for public-facing applications and novice users.

Positioning

SubmitEditSaveCopyDraft
Don't group more than 3 actions together. Consider using an overflow menu for additional options.
SubmitCancel
Use a button group when putting multiple buttons together.
All GoA Design System components are built to meet WCAG 2.2 AA standards. The following guidelines provide additional context for accessible implementation.

Screen Readers

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”.

Don't read the icon class or description for icon buttons with labels. Screen readers should read the button label only.
Icon-only buttons must include a descriptive label for screen readers.

Focus

Don't focus on just the icon within a button. Focus the button as a whole.