Block

Group components into a block with consistent space between.

Props

gap
Spacing
Spacing between items. Uses design system spacing tokens.
Defaults to m.
direction
row | column
Stacking direction of child components.
Defaults to row.
alignment
center | start | end | normal
Primary axis alignment of child components.
Defaults to normal.
testId
string
Sets a data-testid attribute for automated testing.
minWidth
string
Sets the minimum width of the block container.
maxWidth
string
Sets the maximum width of the block container.
width
string
Sets the width of the block container. Defaults to max-content.
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.
Examples

Restricted access (401)

.error-page-content {
  text-align: center;
}
.error-page-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 7.5rem;
  height: 7.5rem;
  border-radius: 50%;
  background-color: var(--goa-color-greyscale-100);
}
/* Icon scaled beyond xlarge (2.5rem cap) to match the page-scale visual weight. */
/* Tracked in icon-sizes-above-xlarge gap ticket. */
.error-page-icon goa-icon,
.error-page-icon goab-icon {
  transform: scale(1.35);
}
.error-page-underline {
  width: 6.875rem;
  height: var(--goa-space-xs);
  background-color: var(--goa-color-info-default);
}
<GoabPageBlock>
  <div className="error-page-content">
    <GoabBlock
      direction="column"
      alignment="center"
      gap="xl"
      width="100%"
      mt="3xl"
      mb="3xl"
    >
      <GoabBlock direction="column" alignment="center" gap="m" width="100%">
        <div className="error-page-icon">
          <GoabIcon role="presentation" type="warning" size="xlarge" />
        </div>
        <GoabText size="body-m" color="secondary" mt="none" mb="none">
          Error 401
        </GoabText>
        <div className="error-page-underline" aria-hidden="true" />
      </GoabBlock>

      <GoabBlock direction="column" alignment="center" gap="l" width="100%">
        <GoabText tag="h1" size="heading-l" mt="none" mb="none">
          Restricted access
        </GoabText>
        <GoabText size="body-m" mt="none" mb="none">
          We cannot provide access to this page without valid credentials. Please sign in or
          contact support at{" "}
          <GoabLink>
            <a href="mailto:cs.licensingsupport@gov.ab.ca">cs.licensingsupport@gov.ab.ca</a>
          </GoabLink>{" "}
          to request access.
        </GoabText>
      </GoabBlock>

      <GoabButton type="primary" size="compact" onClick={() => (window.location.href = "/")}>
        Go to home page
      </GoabButton>
    </GoabBlock>
  </div>
</GoabPageBlock>
goHome() {
  window.location.href = "/";
}
<goab-page-block>
  <div class="error-page-content">
    <goab-block direction="column" alignment="center" gap="xl" width="100%" mt="3xl" mb="3xl">
      <goab-block direction="column" alignment="center" gap="m" width="100%">
        <div class="error-page-icon">
          <goab-icon role="presentation" type="warning" size="xlarge"></goab-icon>
        </div>
        <goab-text size="body-m" color="secondary" mt="none" mb="none">Error 401</goab-text>
        <div class="error-page-underline" aria-hidden="true"></div>
      </goab-block>

      <goab-block direction="column" alignment="center" gap="l" width="100%">
        <goab-text tag="h1" size="heading-l" mt="none" mb="none">Restricted access</goab-text>
        <goab-text size="body-m" mt="none" mb="none">
          We cannot provide access to this page without valid credentials. Please sign in or
          contact support at
          <goab-link>
            <a href="mailto:cs.licensingsupport@gov.ab.ca">cs.licensingsupport@gov.ab.ca</a>
          </goab-link>
          to request access.
        </goab-text>
      </goab-block>

      <goab-button type="primary" size="compact" (onClick)="goHome()">Go to home page</goab-button>
    </goab-block>
  </div>
</goab-page-block>
<goa-page-block>
  <div style="text-align: center;">
    <goa-block direction="column" alignment="center" gap="xl" width="100%" mt="3xl" mb="3xl">
      <goa-block direction="column" alignment="center" gap="m" width="100%">
        <div
          style="display: flex; align-items: center; justify-content: center; width: 7.5rem; height: 7.5rem; border-radius: 50%; background-color: var(--goa-color-greyscale-100);"
        >
          <goa-icon role="presentation" type="warning" size="xlarge" style="transform: scale(1.35);"></goa-icon>
        </div>
        <goa-text size="body-m" color="secondary" mt="none" mb="none">Error 401</goa-text>
        <div
          aria-hidden="true"
          style="width: 6.875rem; height: 0.5rem; background-color: var(--goa-color-info-default);"
        ></div>
      </goa-block>

      <goa-block direction="column" alignment="center" gap="l" width="100%">
        <goa-text as="h1" size="heading-l" mt="none" mb="none">Restricted access</goa-text>
        <goa-text size="body-m" mt="none" mb="none">
          We cannot provide access to this page without valid credentials. Please sign in or
          contact support at
          <goa-link>
            <a href="mailto:cs.licensingsupport@gov.ab.ca">cs.licensingsupport@gov.ab.ca</a>
          </goa-link>
          to request access.
        </goa-text>
      </goa-block>

      <goa-button version="2" type="primary" size="compact" onclick="window.location.href='/'">Go to home page</goa-button>
    </goa-block>
  </div>
</goa-page-block>

Uses a plain h1 as the page landmark. The decorative icon and accent bar are aria-hidden. The support email is a real mailto link inside GoabLink so keyboard users can activate it. No role="alert" is applied because the ARIA alert role is reserved for dynamically inserted messages.

Server problem (500)

.error-page-content {
  text-align: center;
}
.error-page-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 7.5rem;
  height: 7.5rem;
  border-radius: 50%;
  background-color: var(--goa-color-greyscale-100);
}
/* Icon scaled beyond xlarge (2.5rem cap) to match the page-scale visual weight. */
/* Tracked in icon-sizes-above-xlarge gap ticket. */
.error-page-icon goa-icon,
.error-page-icon goab-icon {
  transform: scale(1.35);
}
.error-page-underline {
  width: 6.875rem;
  height: var(--goa-space-xs);
  background-color: var(--goa-color-info-default);
}
<GoabPageBlock>
  <div className="error-page-content">
    <GoabBlock
      direction="column"
      alignment="center"
      gap="xl"
      width="100%"
      mt="3xl"
      mb="3xl"
    >
      <GoabBlock direction="column" alignment="center" gap="m" width="100%">
        <div className="error-page-icon">
          <GoabIcon role="presentation" type="warning" size="xlarge" />
        </div>
        <GoabText size="body-m" color="secondary" mt="none" mb="none">
          Error 500
        </GoabText>
        <div className="error-page-underline" aria-hidden="true" />
      </GoabBlock>

      <GoabBlock direction="column" alignment="center" gap="l" width="100%">
        <GoabText tag="h1" size="heading-l" mt="none" mb="none">
          We are experiencing a problem
        </GoabText>
        <GoabText size="body-m" mt="none" mb="none">
          We cannot load this page right now. Please try again in a few minutes. We apologize
          for the inconvenience.
        </GoabText>
      </GoabBlock>

      <GoabButton type="primary" size="compact" onClick={() => (window.location.href = "/")}>
        Go to home page
      </GoabButton>
    </GoabBlock>
  </div>
</GoabPageBlock>
goHome() {
  window.location.href = "/";
}
<goab-page-block>
  <div class="error-page-content">
    <goab-block direction="column" alignment="center" gap="xl" width="100%" mt="3xl" mb="3xl">
      <goab-block direction="column" alignment="center" gap="m" width="100%">
        <div class="error-page-icon">
          <goab-icon role="presentation" type="warning" size="xlarge"></goab-icon>
        </div>
        <goab-text size="body-m" color="secondary" mt="none" mb="none">Error 500</goab-text>
        <div class="error-page-underline" aria-hidden="true"></div>
      </goab-block>

      <goab-block direction="column" alignment="center" gap="l" width="100%">
        <goab-text tag="h1" size="heading-l" mt="none" mb="none">We are experiencing a problem</goab-text>
        <goab-text size="body-m" mt="none" mb="none">
          We cannot load this page right now. Please try again in a few minutes. We apologize for the inconvenience.
        </goab-text>
      </goab-block>

      <goab-button type="primary" size="compact" (onClick)="goHome()">Go to home page</goab-button>
    </goab-block>
  </div>
</goab-page-block>
<goa-page-block>
  <div style="text-align: center;">
    <goa-block direction="column" alignment="center" gap="xl" width="100%" mt="3xl" mb="3xl">
      <goa-block direction="column" alignment="center" gap="m" width="100%">
        <div
          style="display: flex; align-items: center; justify-content: center; width: 7.5rem; height: 7.5rem; border-radius: 50%; background-color: var(--goa-color-greyscale-100);"
        >
          <goa-icon role="presentation" type="warning" size="xlarge" style="transform: scale(1.35);"></goa-icon>
        </div>
        <goa-text size="body-m" color="secondary" mt="none" mb="none">Error 500</goa-text>
        <div
          aria-hidden="true"
          style="width: 6.875rem; height: 0.5rem; background-color: var(--goa-color-info-default);"
        ></div>
      </goa-block>

      <goa-block direction="column" alignment="center" gap="l" width="100%">
        <goa-text as="h1" size="heading-l" mt="none" mb="none">We are experiencing a problem</goa-text>
        <goa-text size="body-m" mt="none" mb="none">
          We cannot load this page right now. Please try again in a few minutes. We apologize for the inconvenience.
        </goa-text>
      </goa-block>

      <goa-button version="2" type="primary" size="compact" onclick="window.location.href='/'">Go to home page</goa-button>
    </goa-block>
  </div>
</goa-page-block>

Uses a plain h1 as the page landmark. The decorative icon and accent bar are aria-hidden. No role="alert" is applied because the ARIA alert role is reserved for dynamically inserted messages; a static error route does not meet that criterion.

Page not found (404)

.error-page-content {
  text-align: center;
}
.error-page-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 7.5rem;
  height: 7.5rem;
  border-radius: 50%;
  background-color: var(--goa-color-greyscale-100);
}
/* Icon scaled beyond xlarge (2.5rem cap) to match the page-scale visual weight. */
/* Tracked in icon-sizes-above-xlarge gap ticket. */
.error-page-icon goa-icon,
.error-page-icon goab-icon {
  transform: scale(1.35);
}
.error-page-underline {
  width: 6.875rem;
  height: var(--goa-space-xs);
  background-color: var(--goa-color-info-default);
}
<GoabPageBlock>
  <div className="error-page-content">
    <GoabBlock
      direction="column"
      alignment="center"
      gap="xl"
      width="100%"
      mt="3xl"
      mb="3xl"
    >
      <GoabBlock direction="column" alignment="center" gap="m" width="100%">
        <div className="error-page-icon">
          <GoabIcon role="presentation" type="warning" size="xlarge" />
        </div>
        <GoabText size="body-m" color="secondary" mt="none" mb="none">
          Error 404
        </GoabText>
        <div className="error-page-underline" aria-hidden="true" />
      </GoabBlock>

      <GoabBlock direction="column" alignment="center" gap="l" width="100%">
        <GoabText tag="h1" size="heading-l" mt="none" mb="none">
          Page not found
        </GoabText>
        <GoabText size="body-m" mt="none" mb="none">
          The page you're looking for doesn't exist or has been moved.
        </GoabText>
      </GoabBlock>

      <GoabButton type="primary" size="compact" onClick={() => (window.location.href = "/")}>
        Go to home page
      </GoabButton>
    </GoabBlock>
  </div>
</GoabPageBlock>
goHome() {
  window.location.href = "/";
}
<goab-page-block>
  <div class="error-page-content">
    <goab-block direction="column" alignment="center" gap="xl" width="100%" mt="3xl" mb="3xl">
      <goab-block direction="column" alignment="center" gap="m" width="100%">
        <div class="error-page-icon">
          <goab-icon role="presentation" type="warning" size="xlarge"></goab-icon>
        </div>
        <goab-text size="body-m" color="secondary" mt="none" mb="none">Error 404</goab-text>
        <div class="error-page-underline" aria-hidden="true"></div>
      </goab-block>

      <goab-block direction="column" alignment="center" gap="l" width="100%">
        <goab-text tag="h1" size="heading-l" mt="none" mb="none">Page not found</goab-text>
        <goab-text size="body-m" mt="none" mb="none">The page you're looking for doesn't exist or has been moved.</goab-text>
      </goab-block>

      <goab-button type="primary" size="compact" (onClick)="goHome()">Go to home page</goab-button>
    </goab-block>
  </div>
</goab-page-block>
<goa-page-block>
  <div style="text-align: center;">
    <goa-block direction="column" alignment="center" gap="xl" width="100%" mt="3xl" mb="3xl">
      <goa-block direction="column" alignment="center" gap="m" width="100%">
        <div
          style="display: flex; align-items: center; justify-content: center; width: 7.5rem; height: 7.5rem; border-radius: 50%; background-color: var(--goa-color-greyscale-100);"
        >
          <goa-icon role="presentation" type="warning" size="xlarge" style="transform: scale(1.35);"></goa-icon>
        </div>
        <goa-text size="body-m" color="secondary" mt="none" mb="none">Error 404</goa-text>
        <div
          aria-hidden="true"
          style="width: 6.875rem; height: 0.5rem; background-color: var(--goa-color-info-default);"
        ></div>
      </goa-block>

      <goa-block direction="column" alignment="center" gap="l" width="100%">
        <goa-text as="h1" size="heading-l" mt="none" mb="none">Page not found</goa-text>
        <goa-text size="body-m" mt="none" mb="none">The page you're looking for doesn't exist or has been moved.</goa-text>
      </goa-block>

      <goa-button version="2" type="primary" size="compact" onclick="window.location.href='/'">Go to home page</goa-button>
    </goa-block>
  </div>
</goa-page-block>

Uses a plain h1 as the page landmark. The decorative icon and accent bar are aria-hidden. No role="alert" is applied because the ARIA alert role is reserved for dynamically inserted messages; a static error route does not meet that criterion.

Add a record using a drawer

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 alignment="start">
      <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>
open = false;

onClick() {
  this.open = true;
}

onClose() {
  this.open = false;
}

dropdownOnChange(event: any) {
  console.log(event);
}

inputOnChange(event: any) {
  console.log(event);
}

radioOnChange(event: any) {
  console.log(event);
}

dateOnChange(event: any) {
  console.log(event);
}

closeDrawer() {
  this.open = false;
}
<goab-button leadingIcon="add" (onClick)="onClick()">Add Record</goab-button>
<goab-drawer
  maxSize="492px"
  [open]="open"
  heading="Add Record"
  position="right"
  (onClose)="onClose()"
  [actions]="actions"
>
  <goab-form-item label="Level of education">
    <goab-dropdown
      (onChange)="dropdownOnChange($event)"
      name="education"
      value="university"
    >
      <goab-dropdown-item
        value="high-school"
        label="High School Diploma"
      ></goab-dropdown-item>
      <goab-dropdown-item value="college" label="College Diploma"></goab-dropdown-item>
      <goab-dropdown-item
        value="university"
        label="University Degree"
      ></goab-dropdown-item>
      <goab-dropdown-item value="masters" label="Master's Degree"></goab-dropdown-item>
      <goab-dropdown-item value="doctorate" label="Doctorate"></goab-dropdown-item>
    </goab-dropdown>
  </goab-form-item>
  <goab-form-item label="Educational institution" mt="l">
    <goab-input
      name="education"
      type="text"
      (onChange)="inputOnChange($event)"
    ></goab-input>
  </goab-form-item>
  <goab-form-item label="Field of study" requirement="optional" mt="l">
    <goab-input
      name="fieldOfStudy"
      type="text"
      (onChange)="inputOnChange($event)"
    ></goab-input>
  </goab-form-item>
  <goab-form-item label="Is the person currently attending?" mt="l">
    <goab-radio-group
      name="attendTraining"
      orientation="horizontal"
      (onChange)="radioOnChange($event)"
    >
      <goab-radio-item value="yes" label="Yes"></goab-radio-item>
      <goab-radio-item value="no" label="No"></goab-radio-item>
    </goab-radio-group>
  </goab-form-item>
  <goab-form-item label="Start date" mt="l">
    <goab-date-picker (onChange)="dateOnChange($event)"></goab-date-picker>
    <goab-checkbox
      name="startDateApproximate"
      text="Approximate date"
      value="y"
      mt="s"
    ></goab-checkbox>
  </goab-form-item>
  <goab-form-item label="Credential received?" mt="l">
    <goab-radio-group
      name="credentialReceived"
      orientation="horizontal"
      (onChange)="radioOnChange($event)"
    >
      <goab-radio-item value="yes" label="Yes"></goab-radio-item>
      <goab-radio-item value="no" label="No"></goab-radio-item>
    </goab-radio-group>
  </goab-form-item>
  <ng-template #actions>
    <goab-button-group alignment="start">
      <goab-button type="primary" size="compact" (onClick)="closeDrawer()"
        >Add record</goab-button
      >
      <goab-button type="tertiary" size="compact" (onClick)="closeDrawer()"
        >Cancel</goab-button
      >
    </goab-button-group>
  </ng-template>
</goab-drawer>
const drawer = document.getElementById("record-drawer");
const openBtn = document.getElementById("open-drawer-btn");
const addBtn = document.getElementById("add-record-btn");
const cancelBtn = document.getElementById("cancel-btn");

openBtn.addEventListener("_click", () => {
  drawer.setAttribute("open", "true");
});

drawer.addEventListener("_close", () => {
  drawer.removeAttribute("open");
});

addBtn.addEventListener("_click", () => {
  drawer.removeAttribute("open");
});

cancelBtn.addEventListener("_click", () => {
  drawer.removeAttribute("open");
});
<goa-button version="2" id="open-drawer-btn" leadingicon="add">Add Record</goa-button>
<goa-drawer
  version="2"
  id="record-drawer"
  max-size="492px"
  heading="Add Record"
  position="right"
>
  <goa-form-item version="2" label="Level of education">
    <goa-dropdown version="2" name="education" value="university">
      <goa-dropdown-item
        value="high-school"
        label="High School Diploma"
      ></goa-dropdown-item>
      <goa-dropdown-item value="college" label="College Diploma"></goa-dropdown-item>
      <goa-dropdown-item value="university" label="University Degree"></goa-dropdown-item>
      <goa-dropdown-item value="masters" label="Master's Degree"></goa-dropdown-item>
      <goa-dropdown-item value="doctorate" label="Doctorate"></goa-dropdown-item>
    </goa-dropdown>
  </goa-form-item>
  <goa-form-item version="2" label="Educational institution" mt="l">
    <goa-input version="2" name="education" type="text"></goa-input>
  </goa-form-item>
  <goa-form-item version="2" label="Field of study" requirement="optional" mt="l">
    <goa-input version="2" name="fieldOfStudy" type="text"></goa-input>
  </goa-form-item>
  <goa-form-item version="2" label="Is the person currently attending?" mt="l">
    <goa-radio-group version="2" name="attendTraining" orientation="horizontal">
      <goa-radio-item value="yes" label="Yes"></goa-radio-item>
      <goa-radio-item value="no" label="No"></goa-radio-item>
    </goa-radio-group>
  </goa-form-item>
  <goa-form-item version="2" label="Start date" mt="l">
    <goa-date-picker version="2"></goa-date-picker>
    <goa-checkbox
      version="2"
      name="startDateApproximate"
      text="Approximate date"
      value="y"
      mt="s"
    ></goa-checkbox>
  </goa-form-item>
  <goa-form-item version="2" label="Credential received?" mt="l">
    <goa-radio-group version="2" name="credentialReceived" orientation="horizontal">
      <goa-radio-item value="yes" label="Yes"></goa-radio-item>
      <goa-radio-item value="no" label="No"></goa-radio-item>
    </goa-radio-group>
  </goa-form-item>
  <div slot="actions">
    <goa-button-group alignment="start">
      <goa-button version="2" id="add-record-btn" type="primary" size="compact"
        >Add record</goa-button
      >
      <goa-button version="2" id="cancel-btn" type="tertiary" size="compact"
        >Cancel</goa-button
      >
    </goa-button-group>
  </div>
</goa-drawer>

Ask a user for an address

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}
      width="100%"
    >
      <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>
form!: FormGroup;

constructor(private fb: FormBuilder) {
  this.form = this.fb.group({
    address: [""],
    suite: [""],
    city: [""],
    province: [""],
    postalCode: [""],
  });
}

onClick() {
  // Handle form submission
}
<goab-text size="heading-l" mt="none" mb="xl">What is your address?</goab-text>
<goab-form-item label="Street Address">
  <goab-input
    name="address"
    type="text"
    [formControl]="form.controls.address"
    width="100%"
  ></goab-input>
</goab-form-item>
<goab-form-item label="Suite or unit #" mt="l">
  <goab-input
    name="suite"
    type="text"
    [formControl]="form.controls.suite"
    width="100%"
  ></goab-input>
</goab-form-item>
<goab-form-item label="City or town" mt="l">
  <goab-input
    name="city"
    type="text"
    [formControl]="form.controls.city"
    width="100%"
  ></goab-input>
</goab-form-item>
<goab-block direction="row" gap="l" mt="l">
  <goab-form-item label="Province or territory">
    <goab-dropdown name="province" [formControl]="form.controls.province" width="100%">
      <goab-dropdown-item label="Alberta" value="AB"></goab-dropdown-item>
      <goab-dropdown-item label="British Columbia" value="BC"></goab-dropdown-item>
      <goab-dropdown-item label="Manitoba" value="MB"></goab-dropdown-item>
      <goab-dropdown-item label="New Brunswick" value="NB"></goab-dropdown-item>
      <goab-dropdown-item
        label="Newfoundland and Labrador"
        value="NL"
      ></goab-dropdown-item>
      <goab-dropdown-item label="Northwest Territories" value="NT"></goab-dropdown-item>
      <goab-dropdown-item label="Nova Scotia" value="NS"></goab-dropdown-item>
      <goab-dropdown-item label="Nunavut" value="NU"></goab-dropdown-item>
      <goab-dropdown-item label="Ontario" value="ON"></goab-dropdown-item>
      <goab-dropdown-item label="Prince Edward Island" value="PE"></goab-dropdown-item>
      <goab-dropdown-item label="Quebec" value="QC"></goab-dropdown-item>
      <goab-dropdown-item label="Saskatchewan" value="SK"></goab-dropdown-item>
      <goab-dropdown-item label="Yukon" value="YT"></goab-dropdown-item>
    </goab-dropdown>
  </goab-form-item>
  <goab-form-item label="Postal Code">
    <goab-input
      name="postalCode"
      type="text"
      [formControl]="form.controls.postalCode"
      width="7ch"
    ></goab-input>
  </goab-form-item>
</goab-block>
<goab-button-group alignment="start" mt="2xl">
  <goab-button type="primary" (onClick)="onClick()">Save and continue</goab-button>
  <goab-button type="secondary" (onClick)="onClick()">Cancel</goab-button>
</goab-button-group>
document.getElementById("save-btn")?.addEventListener("_click", () => {
  console.log("Form submitted");
});
<goa-text size="heading-l" mt="none" mb="xl">What is your address?</goa-text>
<goa-form-item version="2" label="Street Address">
  <goa-input
    version="2"
    name="address"
    type="text"
    width="100%"
    id="address-input"
  ></goa-input>
</goa-form-item>
<goa-form-item version="2" label="Suite or unit #" mt="l">
  <goa-input
    version="2"
    name="suite"
    type="text"
    width="100%"
    id="suite-input"
  ></goa-input>
</goa-form-item>
<goa-form-item version="2" label="City or town" mt="l">
  <goa-input version="2" name="city" type="text" width="100%" id="city-input"></goa-input>
</goa-form-item>
<goa-block direction="row" gap="l" mt="l">
  <goa-form-item version="2" label="Province or territory">
    <goa-dropdown version="2" name="province" id="province-dropdown" width="100%">
      <goa-dropdown-item label="Alberta" value="AB"></goa-dropdown-item>
      <goa-dropdown-item label="British Columbia" value="BC"></goa-dropdown-item>
      <goa-dropdown-item label="Manitoba" value="MB"></goa-dropdown-item>
      <goa-dropdown-item label="New Brunswick" value="NB"></goa-dropdown-item>
      <goa-dropdown-item label="Newfoundland and Labrador" value="NL"></goa-dropdown-item>
      <goa-dropdown-item label="Northwest Territories" value="NT"></goa-dropdown-item>
      <goa-dropdown-item label="Nova Scotia" value="NS"></goa-dropdown-item>
      <goa-dropdown-item label="Nunavut" value="NU"></goa-dropdown-item>
      <goa-dropdown-item label="Ontario" value="ON"></goa-dropdown-item>
      <goa-dropdown-item label="Prince Edward Island" value="PE"></goa-dropdown-item>
      <goa-dropdown-item label="Quebec" value="QC"></goa-dropdown-item>
      <goa-dropdown-item label="Saskatchewan" value="SK"></goa-dropdown-item>
      <goa-dropdown-item label="Yukon" value="YT"></goa-dropdown-item>
    </goa-dropdown>
  </goa-form-item>
  <goa-form-item version="2" label="Postal Code">
    <goa-input
      version="2"
      name="postalCode"
      type="text"
      width="7ch"
      id="postal-input"
    ></goa-input>
  </goa-form-item>
</goa-block>
<goa-button-group alignment="start" mt="2xl">
  <goa-button version="2" type="primary" id="save-btn">Save and continue</goa-button>
  <goa-button version="2" type="secondary" id="cancel-btn">Cancel</goa-button>
</goa-button-group>

Ask a user for an Indian registration number

const [bandNo, setBandNo] = useState("");
const [family, setFamily] = useState("");
const [position, setPosition] = useState("");
<GoabFormItem label="Indian registration number" labelSize="large">
  <GoabBlock gap="m" direction="row">
    <GoabFormItem label="Band #" helpText="3 digits">
      <GoabInput
        onChange={(e) => setBandNo(e.value)}
        value={bandNo}
        name="bandNo"
        width="88px"
        maxLength={3}
      />
    </GoabFormItem>
    <GoabFormItem label="Family" helpText="Up to 5 digits">
      <GoabInput
        onChange={(e) => setFamily(e.value)}
        value={family}
        name="family"
        width="105px"
        maxLength={5}
      />
    </GoabFormItem>
    <GoabFormItem label="Position" helpText="2 digits">
      <GoabInput
        onChange={(e) => setPosition(e.value)}
        value={position}
        name="position"
        width="71px"
        maxLength={2}
      />
    </GoabFormItem>
  </GoabBlock>
</GoabFormItem>
form!: FormGroup;

constructor(private fb: FormBuilder) {
  this.form = this.fb.group({
    bandNo: [""],
    family: [""],
    position: [""],
  });
}
<form [formGroup]="form">
  <goab-form-item label="Indian registration number" labelSize="large">
    <goab-block gap="m" direction="row">
      <goab-form-item label="Band #" helpText="3 digits">
        <goab-input formControlName="bandNo" name="bandNo" width="88px" [maxLength]="3">
        </goab-input>
      </goab-form-item>
      <goab-form-item label="Family" helpText="Up to 5 digits">
        <goab-input formControlName="family" name="family" width="105px" [maxLength]="5">
        </goab-input>
      </goab-form-item>
      <goab-form-item label="Position" helpText="2 digits">
        <goab-input
          formControlName="position"
          name="position"
          width="71px"
          [maxLength]="2"
        >
        </goab-input>
      </goab-form-item>
    </goab-block>
  </goab-form-item>
</form>
["band-input", "family-input", "position-input"].forEach((id) => {
  document.getElementById(id)?.addEventListener("_change", (e) => {
    console.log(`${id}:`, e.detail.value);
  });
});
<goa-form-item version="2" label="Indian registration number" labelsize="large">
  <goa-block gap="m" direction="row">
    <goa-form-item version="2" label="Band #" helptext="3 digits">
      <goa-input version="2" name="bandNo" id="band-input" width="88px" maxlength="3">
      </goa-input>
    </goa-form-item>
    <goa-form-item version="2" label="Family" helptext="Up to 5 digits">
      <goa-input version="2" name="family" id="family-input" width="105px" maxlength="5">
      </goa-input>
    </goa-form-item>
    <goa-form-item version="2" label="Position" helptext="2 digits">
      <goa-input
        version="2"
        name="position"
        id="position-input"
        width="71px"
        maxlength="2"
      >
      </goa-input>
    </goa-form-item>
  </goa-block>
</goa-form-item>

Card view of case files

.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="default" 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>
<goab-container mt="l">
  <div class="case-file-row">
    <goab-block direction="column" gap="2xs">
      <goab-text size="heading-xs" mt="none" mb="2xs">Fiscal year: 2021/2022</goab-text>
      <goab-text size="body-s" mt="none" mb="none">Submitted: April 23, 2023</goab-text>
    </goab-block>
    <goab-block direction="row" gap="l" alignment="center">
      <goab-badge type="default" content="Not started"></goab-badge>
      <goab-button type="tertiary" size="compact">Start</goab-button>
    </goab-block>
  </div>
</goab-container>

<goab-container>
  <div class="case-file-row">
    <goab-block direction="column" gap="2xs">
      <goab-text size="heading-xs" mt="none" mb="2xs">Fiscal year: 2020/2021</goab-text>
      <goab-text size="body-s" mt="none" mb="none">Submitted: April 9, 2022</goab-text>
    </goab-block>
    <goab-block direction="row" gap="l" alignment="center">
      <goab-badge type="important" content="Information needed"></goab-badge>
      <goab-button type="tertiary" size="compact">Edit</goab-button>
    </goab-block>
  </div>
</goab-container>

<goab-container>
  <div class="case-file-row">
    <goab-block direction="column" gap="2xs">
      <goab-text size="heading-xs" mt="none" mb="2xs">Fiscal year: 2019/2020</goab-text>
      <goab-text size="body-s" mt="none" mb="none">Submitted: April 14, 2021</goab-text>
    </goab-block>
    <goab-block direction="row" gap="l" alignment="center">
      <goab-badge type="success" content="Approved"></goab-badge>
      <goab-button type="tertiary" size="compact">View</goab-button>
    </goab-block>
  </div>
</goab-container>
.case-file-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: var(--goa-space-m);
}
<goa-container mt="l">
  <div class="case-file-row">
    <goa-block direction="column" gap="2xs">
      <goa-text size="heading-xs" mt="none" mb="2xs">Fiscal year: 2021/2022</goa-text>
      <goa-text size="body-s" mt="none" mb="none">Submitted: April 23, 2023</goa-text>
    </goa-block>
    <goa-block direction="row" gap="l" alignment="center">
      <goa-badge version="2" type="default" content="Not started"></goa-badge>
      <goa-button version="2" type="tertiary" size="compact">Start</goa-button>
    </goa-block>
  </div>
</goa-container>

<goa-container>
  <div class="case-file-row">
    <goa-block direction="column" gap="2xs">
      <goa-text size="heading-xs" mt="none" mb="2xs">Fiscal year: 2020/2021</goa-text>
      <goa-text size="body-s" mt="none" mb="none">Submitted: April 9, 2022</goa-text>
    </goa-block>
    <goa-block direction="row" gap="l" alignment="center">
      <goa-badge version="2" type="important" content="Information needed"></goa-badge>
      <goa-button version="2" type="tertiary" size="compact">Edit</goa-button>
    </goa-block>
  </div>
</goa-container>

<goa-container>
  <div class="case-file-row">
    <goa-block direction="column" gap="2xs">
      <goa-text size="heading-xs" mt="none" mb="2xs">Fiscal year: 2019/2020</goa-text>
      <goa-text size="body-s" mt="none" mb="none">Submitted: April 14, 2021</goa-text>
    </goa-block>
    <goa-block direction="row" gap="l" alignment="center">
      <goa-badge version="2" type="success" content="Approved"></goa-badge>
      <goa-button version="2" type="tertiary" size="compact">View</goa-button>
    </goa-block>
  </div>
</goa-container>

Copy to clipboard

.token-block {
  background-color: var(--goa-color-interactive-default);
  height: 22px;
  width: 24px;
  border-radius: var(--goa-border-radius-s);
}
const [isCopied, setIsCopied] = useState(false);

function copyCode() {
  const codeToCopy = "$goa-color-interactive-default";
  navigator.clipboard.writeText(codeToCopy).then(() => {
    setIsCopied(true);
    setTimeout(() => setIsCopied(false), 1000);
  });
}
<GoabBlock alignment="center">
  <div className="token-block" />
  <span>$goa-color-interactive-default</span>
  <GoabTooltip content={isCopied ? "Copied" : "Copy?"} position="top">
    <GoabIconButton icon="copy" onClick={copyCode} mt="2xs" />
  </GoabTooltip>
</GoabBlock>
isCopied = false;

copyCode(): void {
  const codeToCopy = "$goa-color-interactive-default";
  navigator.clipboard.writeText(codeToCopy).then(() => {
    this.isCopied = true;
    setTimeout(() => (this.isCopied = false), 1000);
  });
}
<goab-block alignment="center" gap="s">
  <div class="token-block"></div>
  <span>$goa-color-interactive-default</span>
  <goab-tooltip [content]="isCopied ? 'Copied' : 'Copy?'" position="top">
    <goab-icon-button icon="copy" (onClick)="copyCode()" mt="2xs"></goab-icon-button>
  </goab-tooltip>
</goab-block>
.token-block {
  background-color: var(--goa-color-interactive-default);
  height: 22px;
  width: 24px;
  border-radius: var(--goa-border-radius-s);
}
const copyBtn = document.getElementById("copy-btn");
const tooltip = document.getElementById("copy-tooltip");

function copyCode() {
  const codeToCopy = "$goa-color-interactive-default";
  navigator.clipboard.writeText(codeToCopy).then(() => {
    tooltip.setAttribute("content", "Copied");
    setTimeout(() => {
      tooltip.setAttribute("content", "Copy?");
    }, 1000);
  });
}

copyBtn.addEventListener("_click", copyCode);
<goa-block alignment="center">
  <div class="token-block"></div>
  <span>$goa-color-interactive-default</span>
  <goa-tooltip id="copy-tooltip" content="Copy?" position="top">
    <goa-icon-button id="copy-btn" icon="copy" mt="2xs"></goa-icon-button>
  </goa-tooltip>
</goa-block>

Display user information

const handleAddToCalendar = () => {
  console.log("Add to calendar clicked");
};
<GoabContainer>
  <GoabText tag="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 tag="span" size="heading-xs" mt="none" mb="none">
        Email
      </GoabText>
      <GoabText tag="span" size="heading-xs" mt="none" mb="none">
        Phone
      </GoabText>
    </GoabBlock>
    <GoabBlock direction="column" gap="m">
      <GoabText tag="span" size="body-m" mt="none" mb="none">
        tracyhero@email.com
      </GoabText>
      <GoabText tag="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>
onAddToCalendar(): void {
  console.log("Add to calendar clicked");
}
<goab-container>
  <goab-text tag="span" size="body-m" color="secondary" mt="none" mb="none"
    >Housing Advisor</goab-text
  >
  <goab-text size="heading-m" mt="none" mb="s">Tracy Hero</goab-text>
  <goab-block direction="row" gap="s">
    <goab-block direction="column" gap="m">
      <goab-text tag="span" size="heading-xs" mt="none" mb="none">Email</goab-text>
      <goab-text tag="span" size="heading-xs" mt="none" mb="none">Phone</goab-text>
    </goab-block>
    <goab-block direction="column" gap="m">
      <goab-text tag="span" size="body-m" mt="none" mb="none"
        >tracyhero&#64;email.com</goab-text
      >
      <goab-text tag="span" size="body-m" mt="none" mb="none">283-203-4921</goab-text>
    </goab-block>
  </goab-block>
</goab-container>

<goab-container type="non-interactive" accent="thick">
  <div slot="title">Upcoming important due dates</div>
  <div slot="actions">
    <goab-button
      type="tertiary"
      size="compact"
      leadingIcon="calendar"
      (onClick)="onAddToCalendar()"
    >
      Add to calendar
    </goab-button>
  </div>
  <goab-table width="100%" [striped]="true">
    <tbody>
      <tr>
        <td>Business plan submission</td>
        <td style="text-align: right">June 30, 2024</td>
      </tr>
      <tr>
        <td>Annual review</td>
        <td style="text-align: right">October 3, 2024</td>
      </tr>
      <tr>
        <td>Application submission</td>
        <td style="text-align: right">December 20, 2024</td>
      </tr>
      <tr>
        <td>Application review</td>
        <td style="text-align: right">January 3, 2025</td>
      </tr>
    </tbody>
  </goab-table>
</goab-container>
const calendarBtn = document.getElementById("calendar-btn");
calendarBtn.addEventListener("_click", () => {
  console.log("Add to calendar clicked");
});
<goa-container>
  <goa-text as="span" size="body-m" color="secondary" mt="none" mb="none"
    >Housing Advisor</goa-text
  >
  <goa-text size="heading-m" mt="none" mb="s">Tracy Hero</goa-text>
  <goa-block direction="row" gap="s">
    <goa-block direction="column" gap="m">
      <goa-text as="span" size="heading-xs" mt="none" mb="none">Email</goa-text>
      <goa-text as="span" size="heading-xs" mt="none" mb="none">Phone</goa-text>
    </goa-block>
    <goa-block direction="column" gap="m">
      <goa-text as="span" size="body-m" mt="none" mb="none">tracyhero@email.com</goa-text>
      <goa-text as="span" size="body-m" mt="none" mb="none">283-203-4921</goa-text>
    </goa-block>
  </goa-block>
</goa-container>

<goa-container type="non-interactive" accent="thick">
  <div slot="title">Upcoming important due dates</div>
  <div slot="actions">
    <goa-button
      version="2"
      id="calendar-btn"
      type="tertiary"
      size="compact"
      leadingicon="calendar"
    >
      Add to calendar
    </goa-button>
  </div>
  <goa-table version="2" width="100%" striped="true">
    <table style="width: 100%">
      <tbody>
        <tr>
          <td>Business plan submission</td>
          <td style="text-align: right">June 30, 2024</td>
        </tr>
        <tr>
          <td>Annual review</td>
          <td style="text-align: right">October 3, 2024</td>
        </tr>
        <tr>
          <td>Application submission</td>
          <td style="text-align: right">December 20, 2024</td>
        </tr>
        <tr>
          <td>Application review</td>
          <td style="text-align: right">January 3, 2025</td>
        </tr>
      </tbody>
    </table>
  </goa-table>
</goa-container>

Filter data in a table

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="100%">
  <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>
)}
typedChips: string[] = [];
inputValue = "";
inputError = "";
readonly errorEmpty = "Empty filter";
readonly errorDuplicate = "Enter a unique filter";

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

dataFiltered = this.getFilteredData(this.typedChips);

handleInputChange(detail: GoabInputOnChangeDetail): void {
  const newValue = detail.value.trim();
  this.inputValue = newValue;
}

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

applyFilter(): void {
  if (this.inputValue === "") {
    this.inputError = this.errorEmpty;
    return;
  }
  if (this.typedChips.includes(this.inputValue)) {
    this.inputError = this.errorDuplicate;
    return;
  }
  this.typedChips = [...this.typedChips, this.inputValue];
  this.inputValue = "";
  this.inputError = "";
  this.dataFiltered = this.getFilteredData(this.typedChips);
}

removeTypedChip(chip: string): void {
  this.typedChips = this.typedChips.filter((c) => c !== chip);
  this.dataFiltered = this.getFilteredData(this.typedChips);
  this.inputError = "";
}

removeAllTypedChips(): void {
  this.typedChips = [];
  this.dataFiltered = this.getFilteredData(this.typedChips);
  this.inputError = "";
}

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

checkNested(obj: object, chip: string): boolean {
  return Object.values(obj).some((value) =>
    typeof value === "object" && value !== null
      ? this.checkNested(value, chip)
      : typeof value === "string" && value.toLowerCase().includes(chip.toLowerCase()),
  );
}
<goab-form-item id="filterChipInput" [error]="inputError" mb="m">
  <goab-block gap="xs" direction="row" alignment="start" width="100%">
    <div style="flex: 1">
      <goab-input
        name="filterChipInput"
        aria-labelledby="filterChipInput"
        [value]="inputValue"
        leadingIcon="search"
        width="100%"
        (onChange)="handleInputChange($event)"
        (onKeyPress)="handleInputKeyPress($event)"
      >
      </goab-input>
    </div>
    <goab-button type="secondary" (onClick)="applyFilter()" leadingIcon="filter">
      Filter
    </goab-button>
  </goab-block>
</goab-form-item>

@if (typedChips.length > 0) {
<ng-container>
  <goab-text tag="span" color="secondary" mb="xs" mr="xs"> Filter: </goab-text>
  @for (typedChip of typedChips; track typedChip; let index = $index) {
  <goab-filter-chip
    [content]="typedChip"
    mb="xs"
    mr="xs"
    (onClick)="removeTypedChip(typedChip)"
  >
  </goab-filter-chip>
  }
  <goab-button type="tertiary" size="compact" mb="xs" (onClick)="removeAllTypedChips()">
    Clear all
  </goab-button>
</ng-container>
}

<goab-table width="100%">
  <thead>
    <tr>
      <th>Status</th>
      <th>Name</th>
      <th class="goa-table-number-header">ID Number</th>
    </tr>
  </thead>
  <tbody>
    @for (item of dataFiltered; track $index) {
    <tr>
      <td>
        <goab-badge
          [type]="item.status.type"
          [content]="item.status.text"
          [icon]="false"
        ></goab-badge>
      </td>
      <td>{{ item.name }}</td>
      <td class="goa-table-number-column">{{ item.id }}</td>
    </tr>
    }
  </tbody>
</goab-table>

@if (dataFiltered.length === 0 && data.length > 0) {
<goab-block mt="l" mb="l"> No results found </goab-block>
}
const filterInput = document.getElementById("filter-input");
const filterBtn = document.getElementById("filter-btn");
const filterFormItem = document.getElementById("filter-form-item");
const chipsContainer = document.getElementById("chips-container");
const chipsList = document.getElementById("chips-list");
const clearAllBtn = document.getElementById("clear-all-btn");
const tableRows = document.querySelectorAll("tbody tr");

let typedChips = [];

function filterTable() {
  tableRows.forEach((row) => {
    const badge = row.querySelector("goa-badge");
    const badgeText = badge ? badge.getAttribute("content") || "" : "";
    const text = (row.textContent + " " + badgeText).toLowerCase();
    const matches =
      typedChips.length === 0 ||
      typedChips.every((chip) => text.includes(chip.toLowerCase()));
    row.style.display = matches ? "" : "none";
  });
}

function renderChips() {
  chipsList.innerHTML = "";
  typedChips.forEach((chip) => {
    const filterChip = document.createElement("goa-filter-chip");
    filterChip.setAttribute("version", "2");
    filterChip.setAttribute("content", chip);
    filterChip.setAttribute("mb", "xs");
    filterChip.setAttribute("mr", "xs");
    filterChip.addEventListener("_click", () => removeChip(chip));
    chipsList.appendChild(filterChip);
  });
  chipsContainer.style.display = typedChips.length > 0 ? "block" : "none";
  filterTable();
}

function applyFilter() {
  const value = filterInput.value.trim();
  if (value === "") {
    filterFormItem.setAttribute("error", "Empty filter");
    return;
  }
  if (typedChips.includes(value)) {
    filterFormItem.setAttribute("error", "Enter a unique filter");
    return;
  }
  typedChips.push(value);
  filterInput.value = "";
  filterFormItem.removeAttribute("error");
  renderChips();
}

function removeChip(chip) {
  typedChips = typedChips.filter((c) => c !== chip);
  renderChips();
}

filterBtn.addEventListener("_click", applyFilter);
clearAllBtn.addEventListener("_click", () => {
  typedChips = [];
  renderChips();
});
<goa-form-item version="2" id="filter-form-item" mb="m">
  <goa-block gap="xs" direction="row" alignment="center" width="100%">
    <div style="flex: 1">
      <goa-input
        version="2"
        id="filter-input"
        name="filterChipInput"
        leadingicon="search"
        width="100%"
      >
      </goa-input>
    </div>
    <goa-button version="2" id="filter-btn" type="secondary" leadingicon="filter">
      Filter
    </goa-button>
  </goa-block>
</goa-form-item>

<div id="chips-container" style="display: none">
  <goa-text as="span" color="secondary" mb="xs" mr="xs">Filter:</goa-text>
  <span id="chips-list"></span>
  <goa-button version="2" id="clear-all-btn" type="tertiary" size="compact" mb="xs">
    Clear all
  </goa-button>
</div>

<goa-table version="2" width="100%" mt="s">
  <table style="width: 100%">
    <thead>
      <tr>
        <th>Status</th>
        <th>Name</th>
        <th class="goa-table-number-header">ID Number</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>
          <goa-badge
            version="2"
            type="information"
            content="In progress"
            icon="false"
          ></goa-badge>
        </td>
        <td>Ivan Schmidt</td>
        <td class="goa-table-number-column">7838576954</td>
      </tr>
      <tr>
        <td>
          <goa-badge
            version="2"
            type="success"
            content="Completed"
            icon="false"
          ></goa-badge>
        </td>
        <td>Luz Lakin</td>
        <td class="goa-table-number-column">8576953364</td>
      </tr>
      <tr>
        <td>
          <goa-badge
            version="2"
            type="information"
            content="In progress"
            icon="false"
          ></goa-badge>
        </td>
        <td>Keith McGlynn</td>
        <td class="goa-table-number-column">9846041345</td>
      </tr>
      <tr>
        <td>
          <goa-badge
            version="2"
            type="success"
            content="Completed"
            icon="false"
          ></goa-badge>
        </td>
        <td>Melody Frami</td>
        <td class="goa-table-number-column">7385256175</td>
      </tr>
      <tr>
        <td>
          <goa-badge
            version="2"
            type="important"
            content="Updated"
            icon="false"
          ></goa-badge>
        </td>
        <td>Frederick Skiles</td>
        <td class="goa-table-number-column">5807570418</td>
      </tr>
      <tr>
        <td>
          <goa-badge
            version="2"
            type="success"
            content="Completed"
            icon="false"
          ></goa-badge>
        </td>
        <td>Dana Pfannerstill</td>
        <td class="goa-table-number-column">5736306857</td>
      </tr>
    </tbody>
  </table>
</goa-table>

Result page

      <GoabText tag="h1" mt="none">
        You have completed the application
      </GoabText>

      <GoabCallout type="success" heading="Application submitted">
        <GoabText size="body-m" mt="none" mb="s">
          You will receive a copy of the confirmation to the email name@email.com
        </GoabText>
        <GoabText size="body-m" mt="none" mb="none">
          Your reference number is: <strong>1234ABC</strong>
        </GoabText>
      </GoabCallout>

      <GoabText tag="h2" mt="xl" mb="m">
        What happens next
      </GoabText>
      <GoabText size="body-m" mt="none" mb="s">
        We've sent your application to service name. They will contact you to confirm your
        registration.
      </GoabText>
      <GoabText size="body-m" mt="none" mb="s">
        You can now close this window.
      </GoabText>
      <GoabText size="body-m" mt="none" mb="s">
        What did you think of this service? <a href="#">Give feedback</a>
      </GoabText>

      <GoabText tag="h2" mt="xl" mb="m">
        If you have questions about your application
      </GoabText>
      <GoabText size="body-m" mt="none" mb="s">
        Contact the [ministry area].
      </GoabText>
      <GoabText size="body-m" mt="none" mb="s">
        Email: <a href="mailto:information@gov.ab.ca">information@gov.ab.ca</a>
      </GoabText>
      <GoabText size="body-m" mt="none" mb="s">
        Phone: <a href="tel:7801234567">780 123 4567</a>
      </GoabText>
  );
}
<goab-text tag="h1" mt="none">You have completed the application</goab-text>

<goab-callout type="success" heading="Application submitted">
  <goab-text size="body-m" mt="none" mb="s"
    >You will receive a copy of the confirmation to the email
    name&#64;email.com</goab-text
  >
  <goab-text size="body-m" mt="none" mb="none"
    >Your reference number is: <strong>1234ABC</strong></goab-text
  >
</goab-callout>

<goab-text tag="h2" mt="xl" mb="m">What happens next</goab-text>
<goab-text size="body-m" mt="none" mb="s"
  >We've sent your application to service name. They will contact you to confirm your
  registration.</goab-text
>
<goab-text size="body-m" mt="none" mb="s">You can now close this window.</goab-text>
<goab-text size="body-m" mt="none" mb="s"
  >What did you think of this service? <a href="#">Give feedback</a></goab-text
>

<goab-text tag="h2" mt="xl" mb="m"
  >If you have questions about your application</goab-text
>
<goab-text size="body-m" mt="none" mb="s">Contact the [ministry area].</goab-text>
<goab-text size="body-m" mt="none" mb="s"
  >Email:
  <a href="mailto:information&#64;gov.ab.ca">information&#64;gov.ab.ca</a></goab-text
>
<goab-text size="body-m" mt="none" mb="s"
  >Phone: <a href="tel:7801234567">780 123 4567</a></goab-text
>
<goa-text as="h1" mt="none">You have completed the application</goa-text>

<goa-callout version="2" type="success" heading="Application submitted">
  <goa-text size="body-m" mt="none" mb="s"
    >You will receive a copy of the confirmation to the email name@email.com</goa-text
  >
  <goa-text size="body-m" mt="none" mb="none"
    >Your reference number is: <strong>1234ABC</strong></goa-text
  >
</goa-callout>

<goa-text as="h2" mt="xl" mb="m">What happens next</goa-text>
<goa-text size="body-m" mt="none" mb="s"
  >We've sent your application to service name. They will contact you to confirm your
  registration.</goa-text
>
<goa-text size="body-m" mt="none" mb="s">You can now close this window.</goa-text>
<goa-text size="body-m" mt="none" mb="s"
  >What did you think of this service? <a href="#">Give feedback</a></goa-text
>

<goa-text as="h2" mt="xl" mb="m">If you have questions about your application</goa-text>
<goa-text size="body-m" mt="none" mb="s">Contact the [ministry area].</goa-text>
<goa-text size="body-m" mt="none" mb="s"
  >Email: <a href="mailto:information@gov.ab.ca">information@gov.ab.ca</a></goa-text
>
<goa-text size="body-m" mt="none" mb="s"
  >Phone: <a href="tel:7801234567">780 123 4567</a></goa-text
>

Review and action

<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) 12345678"}
      </GoabText>
      <GoabText size="body-m" mt="none" mb="none">
        {"CC 334(1) - Theft under $5000"}
      </GoabText>
      <GoabText size="body-m" mt="none" mb="none">
        {"CC 268(1) - Aggravated assault"}
      </GoabText>
    </GoabContainer>

    <GoabContainer type="non-interactive" padding="compact">
      <GoabText size="heading-xs" mt="none" mb="xs">
        {"2) 12345678"}
      </GoabText>
      <GoabText size="body-m" mt="none" mb="none">
        {"CC 334(1) - Theft under $5000"}
      </GoabText>
      <GoabText size="body-m" mt="none" mb="none">
        {"CC 268(1) - Aggravated assault"}
      </GoabText>
    </GoabContainer>
  </GoabContainer>

  <GoabContainer accent="thin" width="content">
    <form>
      <GoabText size="heading-m" mt="none" mb="m">
        Adjournment request
      </GoabText>
      <GoabText size="body-m" mt="none" mb="none">
        Keep track of the individuals who are placed in lodges and may qualify for the
        Lodge Assistance Program subsidy.
      </GoabText>

      <GoabFormItem label="Case history and new request" mt="l">
        <GoabRadioGroup name="case" orientation="horizontal" onChange={() => {}}>
          <GoabRadioItem value="grant" label="Grant" />
          <GoabRadioItem value="deny" label="Deny" />
        </GoabRadioGroup>
      </GoabFormItem>

      <GoabFormItem label="Reason to deny" mt="l">
        <GoabDropdown name="reason" width="100%" onChange={() => {}}>
          <GoabDropdownItem value="1" label="Incomplete Application" />
          <GoabDropdownItem value="2" label="Eligibility Criteria Not Met" />
          <GoabDropdownItem value="3" label="Documentation Verification Failure" />
        </GoabDropdown>
      </GoabFormItem>

      <GoabFormItem label="Message" mt="l">
        <GoabTextArea
          name="message"
          rows={5}
          width="100%"
          value=""
          onChange={() => {}}
        />
      </GoabFormItem>

      <GoabButton mt="xl" onClick={() => {}}>
        Confirm adjournment
      </GoabButton>
    </form>
  </GoabContainer>
</GoabGrid>
form: FormGroup;

constructor(private fb: FormBuilder) {
  this.form = this.fb.group({
    case: [""],
    reason: [""],
    message: [""],
  });
}

onClick(): void {
  console.log("Confirm clicked!");
}
<goab-grid minChildWidth="315px">
  <goab-container accent="thin" type="non-interactive">
    <goab-text size="heading-m" mt="none" mb="m">Appearance details</goab-text>
    <goab-grid minChildWidth="200px" gap="m">
      <goab-block direction="column" gap="xs">
        <goab-text size="body-s" color="secondary" mt="none" mb="none"
          >Accused name</goab-text
        >
        <goab-text size="body-m" mt="none" mb="none">Doe, John Scott</goab-text>
      </goab-block>

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

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

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

    <goab-text size="heading-xs" mt="l" mb="s">Docket number(s) &amp; charges</goab-text>
    <goab-container type="non-interactive" padding="compact">
      <goab-text size="heading-xs" mt="none" mb="xs">1) 12345678</goab-text>
      <goab-text size="body-m" mt="none" mb="none"
        >CC 334(1) - Theft under $5000</goab-text
      >
      <goab-text size="body-m" mt="none" mb="none"
        >CC 268(1) - Aggravated assault</goab-text
      >
    </goab-container>

    <goab-container type="non-interactive" padding="compact">
      <goab-text size="heading-xs" mt="none" mb="xs">2) 12345678</goab-text>
      <goab-text size="body-m" mt="none" mb="none"
        >CC 334(1) - Theft under $5000</goab-text
      >
      <goab-text size="body-m" mt="none" mb="none"
        >CC 268(1) - Aggravated assault</goab-text
      >
    </goab-container>
  </goab-container>

  <goab-container accent="thin" width="content">
    <form [formGroup]="form">
      <goab-text size="heading-m" mt="none" mb="m">Adjournment request</goab-text>
      <goab-text size="body-m" mt="none" mb="none">
        Keep track of the individuals who are placed in lodges and may qualify for the
        Lodge Assistance Program subsidy.
      </goab-text>

      <goab-form-item label="Case history and new request" mt="l">
        <goab-radio-group name="case" orientation="horizontal" formControlName="case">
          <goab-radio-item value="grant" label="Grant"></goab-radio-item>
          <goab-radio-item value="deny" label="Deny"></goab-radio-item>
        </goab-radio-group>
      </goab-form-item>

      <goab-form-item label="Reason to deny" mt="l">
        <goab-dropdown name="reason" width="100%" formControlName="reason">
          <goab-dropdown-item
            value="1"
            label="Incomplete Application"
          ></goab-dropdown-item>
          <goab-dropdown-item
            value="2"
            label="Eligibility Criteria Not Met"
          ></goab-dropdown-item>
          <goab-dropdown-item
            value="3"
            label="Documentation Verification Failure"
          ></goab-dropdown-item>
        </goab-dropdown>
      </goab-form-item>

      <goab-form-item label="Message" mt="l">
        <goab-textarea
          name="message"
          [rows]="5"
          width="100%"
          formControlName="message"
        ></goab-textarea>
      </goab-form-item>

      <goab-button mt="xl" (onClick)="onClick()">Confirm adjournment</goab-button>
    </form>
  </goab-container>
</goab-grid>
document.getElementById("confirm-btn").addEventListener("_click", () => {
  console.log("Confirm clicked!");
});
<goa-grid minchildwidth="315px">
  <goa-container accent="thin" type="non-interactive">
    <goa-text size="heading-m" mt="none" mb="m">Appearance details</goa-text>
    <goa-grid minchildwidth="200px" gap="m">
      <goa-block direction="column" gap="xs">
        <goa-text size="body-s" color="secondary" mt="none" mb="none"
          >Accused name</goa-text
        >
        <goa-text size="body-m" mt="none" mb="none">Doe, John Scott</goa-text>
      </goa-block>

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

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

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

    <goa-text size="heading-xs" mt="l" mb="s">Docket number(s) &amp; charges</goa-text>
    <goa-container type="non-interactive" padding="compact">
      <goa-text size="heading-xs" mt="none" mb="xs">1) 12345678</goa-text>
      <goa-text size="body-m" mt="none" mb="none">CC 334(1) - Theft under $5000</goa-text>
      <goa-text size="body-m" mt="none" mb="none"
        >CC 268(1) - Aggravated assault</goa-text
      >
    </goa-container>

    <goa-container type="non-interactive" padding="compact">
      <goa-text size="heading-xs" mt="none" mb="xs">2) 12345678</goa-text>
      <goa-text size="body-m" mt="none" mb="none">CC 334(1) - Theft under $5000</goa-text>
      <goa-text size="body-m" mt="none" mb="none"
        >CC 268(1) - Aggravated assault</goa-text
      >
    </goa-container>
  </goa-container>

  <goa-container accent="thin" width="content">
    <form>
      <goa-text size="heading-m" mt="none" mb="m">Adjournment request</goa-text>
      <goa-text size="body-m" mt="none" mb="none">
        Keep track of the individuals who are placed in lodges and may qualify for the
        Lodge Assistance Program subsidy.
      </goa-text>

      <goa-form-item version="2" label="Case history and new request" mt="l">
        <goa-radio-group version="2" name="case" orientation="horizontal">
          <goa-radio-item value="grant" label="Grant"></goa-radio-item>
          <goa-radio-item value="deny" label="Deny"></goa-radio-item>
        </goa-radio-group>
      </goa-form-item>

      <goa-form-item version="2" label="Reason to deny" mt="l">
        <goa-dropdown version="2" name="reason" width="100%">
          <goa-dropdown-item value="1" label="Incomplete Application"></goa-dropdown-item>
          <goa-dropdown-item
            value="2"
            label="Eligibility Criteria Not Met"
          ></goa-dropdown-item>
          <goa-dropdown-item
            value="3"
            label="Documentation Verification Failure"
          ></goa-dropdown-item>
        </goa-dropdown>
      </goa-form-item>

      <goa-form-item version="2" label="Message" mt="l">
        <goa-textarea version="2" name="message" rows="5" width="100%"></goa-textarea>
      </goa-form-item>

      <goa-button version="2" id="confirm-btn" mt="xl">Confirm adjournment</goa-button>
    </form>
  </goa-container>
</goa-grid>
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>
form: FormGroup;

constructor(private fb: FormBuilder) {
  this.form = this.fb.group({
    search: [""],
  });
}

onClick(): void {
  console.log("search:", this.form.controls["search"].value);
}
<form [formGroup]="form">
  <goab-form-item>
    <goab-block gap="xs" direction="row">
      <goab-input
        type="search"
        name="search"
        formControlName="search"
        leadingIcon="search"
      >
      </goab-input>
      <goab-button type="primary" (onClick)="onClick()">Search</goab-button>
    </goab-block>
  </goab-form-item>
</form>
const searchInput = document.getElementById("search-input");
const searchBtn = document.getElementById("search-btn");
let searchValue = "";

searchInput.addEventListener("_change", (e) => {
  searchValue = e.detail.value;
});

searchBtn.addEventListener("_click", () => {
  console.log("search:", searchValue);
});
<form>
  <goa-form-item version="2">
    <goa-block gap="xs" direction="row">
      <goa-input
        version="2"
        id="search-input"
        type="search"
        name="search"
        leadingicon="search"
      >
      </goa-input>
      <goa-button version="2" id="search-btn" type="primary">Search</goa-button>
    </goa-block>
  </goa-form-item>
</form>

Show a list to help answer a question

const handleChange = (event: GoabRadioGroupOnChangeDetail) => {
  console.log("value is", event.value);
};
<form>
  <GoabFormItem
    label="Do you have additional education expenses?"
    helpText="You can request funding for these now or at any time during your program."
    mb="m"
  >
    <GoabRadioGroup name="additional" onChange={handleChange}>
      <GoabRadioItem label="Yes" value="yes" name="additional" />
      <GoabRadioItem label="No" value="no" name="additional" />
    </GoabRadioGroup>
  </GoabFormItem>

  <GoabDetails heading="What are additional education expenses?">
    <GoabBlock gap="m" mt="m">
      <div>
        <strong>Examples of education expenses</strong>
        <ul className="goa-unordered-list">
          <li>Laptop and computer hardware</li>
          <li>Computer apps and subscriptions</li>
          <li>Home internet</li>
          <li>Testing and exam fees</li>
          <li>Work or school clothing, like work boots</li>
        </ul>
      </div>
      <div>
        <strong>Do not include</strong>
        <ul className="goa-unordered-list">
          <li>Tuition</li>
          <li>Mandatory fees</li>
          <li>Books and supplies</li>
          <li>School association fees</li>
        </ul>
      </div>
    </GoabBlock>
  </GoabDetails>
</form>
onRadioChange(event: GoabRadioGroupOnChangeDetail): void {
  console.log("value is", event.value);
}
<form [formGroup]="form">
  <goab-form-item
    label="Do you have additional education expenses?"
    helpText="You can request funding for these now or at any time during your program."
    mb="m"
  >
    <goab-radio-group name="additional" (onChange)="onRadioChange($event)">
      <goab-radio-item label="Yes" value="yes" name="additional"></goab-radio-item>
      <goab-radio-item label="No" value="no" name="additional"></goab-radio-item>
    </goab-radio-group>
  </goab-form-item>

  <goab-details heading="What are additional education expenses?">
    <goab-block gap="m" mt="m">
      <div>
        <strong>Examples of education expenses</strong>
        <ul class="goa-unordered-list">
          <li>Laptop and computer hardware</li>
          <li>Computer apps and subscriptions</li>
          <li>Home internet</li>
          <li>Testing and exam fees</li>
          <li>Work or school clothing, like work boots</li>
        </ul>
      </div>
      <div>
        <strong>Do not include</strong>
        <ul class="goa-unordered-list">
          <li>Tuition</li>
          <li>Mandatory fees</li>
          <li>Books and supplies</li>
          <li>School association fees</li>
        </ul>
      </div>
    </goab-block>
  </goab-details>
</form>
document.querySelector("goa-radio-group").addEventListener("_change", (e) => {
  console.log("value is", e.detail.value);
});
<form>
  <goa-form-item
    version="2"
    label="Do you have additional education expenses?"
    helptext="You can request funding for these now or at any time during your program."
    mb="m"
  >
    <goa-radio-group version="2" name="additional">
      <goa-radio-item label="Yes" value="yes" name="additional"></goa-radio-item>
      <goa-radio-item label="No" value="no" name="additional"></goa-radio-item>
    </goa-radio-group>
  </goa-form-item>

  <goa-details heading="What are additional education expenses?">
    <goa-block gap="m" mt="m">
      <div>
        <strong>Examples of education expenses</strong>
        <ul class="goa-unordered-list">
          <li>Laptop and computer hardware</li>
          <li>Computer apps and subscriptions</li>
          <li>Home internet</li>
          <li>Testing and exam fees</li>
          <li>Work or school clothing, like work boots</li>
        </ul>
      </div>
      <div>
        <strong>Do not include</strong>
        <ul class="goa-unordered-list">
          <li>Tuition</li>
          <li>Mandatory fees</li>
          <li>Books and supplies</li>
          <li>School association fees</li>
        </ul>
      </div>
    </goa-block>
  </goa-details>
</form>

Show multiple actions in a compact table

const rows = [
  {
    status: "information",
    statusText: "In progress",
    name: "Darlene Robertson",
    id: 45904,
  },
  { status: "default", statusText: "Inactive", name: "Floyd Miles", id: 47838 },
  { status: "success", statusText: "Active", name: "Kathryn Murphy", id: 34343 },
  { status: "important", statusText: "Recent", name: "Annette Black", id: 89897 },
  { status: "success", statusText: "Active", name: "Esther Howard", id: 12323 },
  { status: "success", statusText: "Active", name: "Jane Cooper", id: 56565 },
];
<GoabTable width="100%">
  <thead>
    <tr>
      <th>Status</th>
      <th>Name</th>
      <th style={{ textAlign: "right" }}>Id Number</th>
      <th style={{ width: "1%", whiteSpace: "nowrap" }}>Edit | Flag | Send</th>
    </tr>
  </thead>
  <tbody>
    {rows.map((row) => (
      <tr key={row.id}>
        <td>
          <GoabBadge
            type={row.status as "information" | "default" | "success" | "important"}
            content={row.statusText}
            icon={false}
          />
        </td>
        <td>{row.name}</td>
        <td className="goa-table-number-column">{row.id}</td>
        <td>
          <GoabBlock>
            <GoabIconButton size="small" icon="pencil" ariaLabel="Edit" />
            <GoabIconButton size="small" icon="flag" ariaLabel="Flag" />
            <GoabIconButton size="small" icon="mail" ariaLabel="Send" />
          </GoabBlock>
        </td>
      </tr>
    ))}
  </tbody>
</GoabTable>
rows: TableRow[] = [
  {
    status: "information",
    statusText: "In progress",
    name: "Darlene Robertson",
    id: 45904,
  },
  { status: "default", statusText: "Inactive", name: "Floyd Miles", id: 47838 },
  { status: "success", statusText: "Active", name: "Kathryn Murphy", id: 34343 },
  { status: "important", statusText: "Recent", name: "Annette Black", id: 89897 },
  { status: "success", statusText: "Active", name: "Esther Howard", id: 12323 },
  { status: "success", statusText: "Active", name: "Jane Cooper", id: 56565 },
];
<goab-table width="100%">
  <thead>
    <tr>
      <th>Status</th>
      <th>Name</th>
      <th style="text-align: right">Id Number</th>
      <th style="width: 1%; white-space: nowrap">Edit | Flag | Send</th>
    </tr>
  </thead>
  <tbody>
    @for (row of rows; track row.id) {
    <tr>
      <td>
        <goab-badge
          [type]="row.status"
          [content]="row.statusText"
          [icon]="false"
        ></goab-badge>
      </td>
      <td>{{ row.name }}</td>
      <td class="goa-table-number-column">{{ row.id }}</td>
      <td>
        <goab-block>
          <goab-icon-button
            size="small"
            icon="pencil"
            ariaLabel="Edit"
          ></goab-icon-button>
          <goab-icon-button size="small" icon="flag" ariaLabel="Flag"></goab-icon-button>
          <goab-icon-button size="small" icon="mail" ariaLabel="Send"></goab-icon-button>
        </goab-block>
      </td>
    </tr>
    }
  </tbody>
</goab-table>
<goa-table version="2" width="100%">
  <table width="100%">
    <thead>
      <tr>
        <th>Status</th>
        <th>Name</th>
        <th style="text-align: right">Id Number</th>
        <th style="width: 1%; white-space: nowrap">Edit | Flag | Send</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>
          <goa-badge
            version="2"
            type="information"
            content="In progress"
            icon="false"
          ></goa-badge>
        </td>
        <td>Darlene Robertson</td>
        <td class="goa-table-number-column">45904</td>
        <td>
          <goa-block>
            <goa-icon-button
              size="small"
              icon="pencil"
              arialabel="Edit"
            ></goa-icon-button>
            <goa-icon-button size="small" icon="flag" arialabel="Flag"></goa-icon-button>
            <goa-icon-button size="small" icon="mail" arialabel="Send"></goa-icon-button>
          </goa-block>
        </td>
      </tr>
      <tr>
        <td>
          <goa-badge
            version="2"
            type="default"
            content="Inactive"
            icon="false"
          ></goa-badge>
        </td>
        <td>Floyd Miles</td>
        <td class="goa-table-number-column">47838</td>
        <td>
          <goa-block>
            <goa-icon-button
              size="small"
              icon="pencil"
              arialabel="Edit"
            ></goa-icon-button>
            <goa-icon-button size="small" icon="flag" arialabel="Flag"></goa-icon-button>
            <goa-icon-button size="small" icon="mail" arialabel="Send"></goa-icon-button>
          </goa-block>
        </td>
      </tr>
      <tr>
        <td>
          <goa-badge version="2" type="success" content="Active" icon="false"></goa-badge>
        </td>
        <td>Kathryn Murphy</td>
        <td class="goa-table-number-column">34343</td>
        <td>
          <goa-block>
            <goa-icon-button
              size="small"
              icon="pencil"
              arialabel="Edit"
            ></goa-icon-button>
            <goa-icon-button size="small" icon="flag" arialabel="Flag"></goa-icon-button>
            <goa-icon-button size="small" icon="mail" arialabel="Send"></goa-icon-button>
          </goa-block>
        </td>
      </tr>
      <tr>
        <td>
          <goa-badge
            version="2"
            type="important"
            content="Recent"
            icon="false"
          ></goa-badge>
        </td>
        <td>Annette Black</td>
        <td class="goa-table-number-column">89897</td>
        <td>
          <goa-block>
            <goa-icon-button
              size="small"
              icon="pencil"
              arialabel="Edit"
            ></goa-icon-button>
            <goa-icon-button size="small" icon="flag" arialabel="Flag"></goa-icon-button>
            <goa-icon-button size="small" icon="mail" arialabel="Send"></goa-icon-button>
          </goa-block>
        </td>
      </tr>
      <tr>
        <td>
          <goa-badge version="2" type="success" content="Active" icon="false"></goa-badge>
        </td>
        <td>Esther Howard</td>
        <td class="goa-table-number-column">12323</td>
        <td>
          <goa-block>
            <goa-icon-button
              size="small"
              icon="pencil"
              arialabel="Edit"
            ></goa-icon-button>
            <goa-icon-button size="small" icon="flag" arialabel="Flag"></goa-icon-button>
            <goa-icon-button size="small" icon="mail" arialabel="Send"></goa-icon-button>
          </goa-block>
        </td>
      </tr>
      <tr>
        <td>
          <goa-badge version="2" type="success" content="Active" icon="false"></goa-badge>
        </td>
        <td>Jane Cooper</td>
        <td class="goa-table-number-column">56565</td>
        <td>
          <goa-block>
            <goa-icon-button
              size="small"
              icon="pencil"
              arialabel="Edit"
            ></goa-icon-button>
            <goa-icon-button size="small" icon="flag" arialabel="Flag"></goa-icon-button>
            <goa-icon-button size="small" icon="mail" arialabel="Send"></goa-icon-button>
          </goa-block>
        </td>
      </tr>
    </tbody>
  </table>
</goa-table>

Show multiple tags together

<GoabBlock gap="xs">
  <GoabBadge type="information" content="In progress" />
  <GoabBadge type="important" content="Priority" />
  <GoabBadge type="emergency" content="Past deadline" />
</GoabBlock>
<goab-block gap="xs">
  <goab-badge type="information" content="In progress"></goab-badge>
  <goab-badge type="important" content="Priority"></goab-badge>
  <goab-badge type="emergency" content="Past deadline"></goab-badge>
</goab-block>
<goa-block gap="xs">
  <goa-badge version="2" type="information" content="In progress"></goa-badge>
  <goa-badge version="2" type="important" content="Priority"></goa-badge>
  <goa-badge version="2" type="emergency" content="Past deadline"></goa-badge>
</goa-block>

Show number of results per page

interface User {
  id: string;
  firstName: string;
  lastName: string;
  age: number;
}

const [users] = useState<User[]>(() => generateUsers());
const [page, setPage] = useState<number>(1);
const [perPage, setPerPage] = useState<number>(10);

const offset = (page - 1) * perPage;
const pageUsers = users.slice(offset, offset + perPage);

function changePage(newPage: number) {
  setPage(newPage);
}

function handlePerPageCountChangeEvent(event: GoabDropdownOnChangeDetail) {
  setPage(1);
  setPerPage(parseInt(event.value || "10"));
}
<GoabTable width="100%" mb="xl">
  <thead>
    <tr>
      <th>First name</th>
      <th>Last name</th>
      <th>Age</th>
    </tr>
  </thead>
  <tbody>
    {pageUsers.map((u) => (
      <tr key={u.id}>
        <td>{u.firstName}</td>
        <td>{u.lastName}</td>
        <td>{u.age}</td>
      </tr>
    ))}
  </tbody>
</GoabTable>

<GoabBlock alignment="center" width="100%">
  <GoabBlock mb="m" alignment="center">
    Show
    <GoabDropdown
      onChange={handlePerPageCountChangeEvent}
      value={perPage.toString()}
      width="9ch"
    >
      <GoabDropdownItem value="10" label="10" />
      <GoabDropdownItem value="20" label="20" />
      <GoabDropdownItem value="30" label="30" />
    </GoabDropdown>
    <span style={{ width: "75px" }}>per page</span>
  </GoabBlock>
  <GoabSpacer hSpacing="fill" />
  <GoabPagination
    itemCount={users.length}
    perPageCount={perPage}
    pageNumber={page}
    onChange={(event) => changePage(event.page)}
  />
</GoabBlock>
  users: User[] = generateUsers();
  page = 1;
  perPage = 10;

  get pageUsers(): User[] {
    const offset = (this.page - 1) * this.perPage;
    return this.users.slice(offset, offset + this.perPage);
  }

  handlePageChange(event: GoabPaginationOnChangeDetail): void {
    this.page = event.page;
  }

  handlePerPageCountChangeEvent(event: GoabDropdownOnChangeDetail): void {
    this.page = 1;
    this.perPage = Number(event.value);
  }
}

function generateUsers(): User[] {
  const firstNames = [
    "Emma",
    "Liam",
    "Olivia",
    "Noah",
    "Ava",
    "James",
    "Sophia",
    "William",
    "Isabella",
    "Oliver",
    "Mia",
    "Benjamin",
    "Charlotte",
    "Elijah",
    "Amelia",
    "Lucas",
    "Harper",
    "Mason",
    "Evelyn",
    "Logan",
  ];
  const lastNames = [
    "Smith",
    "Johnson",
    "Williams",
    "Brown",
    "Jones",
    "Garcia",
    "Miller",
    "Davis",
    "Rodriguez",
    "Martinez",
    "Wilson",
    "Anderson",
    "Taylor",
    "Thomas",
    "Moore",
    "Jackson",
    "Martin",
    "Lee",
    "Thompson",
    "White",
  ];
  const users: User[] = [];
  for (let i = 1; i <= 100; i++) {
    users.push({
      id: `user-${i}`,
      firstName: firstNames[(i - 1) % firstNames.length],
      lastName: lastNames[(i - 1) % lastNames.length],
      age: 20 + (i % 40),
    });
  }
  return users;
<goab-table width="100%" mb="xl">
  <thead>
    <tr>
      <th>First name</th>
      <th>Last name</th>
      <th>Age</th>
    </tr>
  </thead>
  <tbody>
    @for (user of pageUsers; track $index) {
    <tr>
      <td>{{ user.firstName }}</td>
      <td>{{ user.lastName }}</td>
      <td>{{ user.age }}</td>
    </tr>
    }
  </tbody>
</goab-table>

<goab-block alignment="center" width="100%">
  <goab-block mb="m" alignment="center">
    Show
    <goab-dropdown
      (onChange)="handlePerPageCountChangeEvent($event)"
      [value]="perPage.toString()"
      width="9ch"
    >
      <goab-dropdown-item value="10" label="10"></goab-dropdown-item>
      <goab-dropdown-item value="20" label="20"></goab-dropdown-item>
      <goab-dropdown-item value="30" label="30"></goab-dropdown-item>
    </goab-dropdown>
    <span style="width: 75px">per page</span>
  </goab-block>

  <goab-spacer hSpacing="fill"></goab-spacer>

  <goab-pagination
    [itemCount]="users.length"
    [perPageCount]="perPage"
    [pageNumber]="page"
    (onChange)="handlePageChange($event)"
  >
  </goab-pagination>
</goab-block>
const firstNames = [
  "Emma",
  "Liam",
  "Olivia",
  "Noah",
  "Ava",
  "James",
  "Sophia",
  "William",
  "Isabella",
  "Oliver",
  "Mia",
  "Benjamin",
  "Charlotte",
  "Elijah",
  "Amelia",
  "Lucas",
  "Harper",
  "Mason",
  "Evelyn",
  "Logan",
];
const lastNames = [
  "Smith",
  "Johnson",
  "Williams",
  "Brown",
  "Jones",
  "Garcia",
  "Miller",
  "Davis",
  "Rodriguez",
  "Martinez",
  "Wilson",
  "Anderson",
  "Taylor",
  "Thomas",
  "Moore",
  "Jackson",
  "Martin",
  "Lee",
  "Thompson",
  "White",
];
const users = [];
for (let i = 1; i <= 100; i++) {
  users.push({
    id: "user-" + i,
    firstName: firstNames[(i - 1) % firstNames.length],
    lastName: lastNames[(i - 1) % lastNames.length],
    age: 20 + (i % 40),
  });
}

let page = 1;
let perPage = 10;

const tableBody = document.getElementById("table-body");
const pagination = document.getElementById("pagination");
const dropdown = document.getElementById("per-page-dropdown");

function renderTable() {
  const offset = (page - 1) * perPage;
  const pageUsers = users.slice(offset, offset + perPage);

  tableBody.innerHTML = pageUsers
    .map(
      (u) => `
      <tr>
        <td>${u.firstName}</td>
        <td>${u.lastName}</td>
        <td>${u.age}</td>
      </tr>
    `,
    )
    .join("");
}

pagination.addEventListener("_change", (e) => {
  page = e.detail.page;
  renderTable();
});

dropdown.addEventListener("_change", (e) => {
  perPage = parseInt(e.detail.value);
  page = 1;
  pagination.setAttribute("perpagecount", perPage);
  pagination.setAttribute("pagenumber", "1");
  renderTable();
});

renderTable();
<goa-table version="2" width="100%" mb="xl">
  <table width="100%">
    <thead>
      <tr>
        <th>First name</th>
        <th>Last name</th>
        <th>Age</th>
      </tr>
    </thead>
    <tbody id="table-body">
      <!-- Rows populated by JavaScript -->
    </tbody>
  </table>
</goa-table>

<goa-block alignment="center" width="100%">
  <goa-block mb="m" alignment="center">
    Show
    <goa-dropdown version="2" id="per-page-dropdown" value="10" width="9ch">
      <goa-dropdown-item value="10" label="10"></goa-dropdown-item>
      <goa-dropdown-item value="20" label="20"></goa-dropdown-item>
      <goa-dropdown-item value="30" label="30"></goa-dropdown-item>
    </goa-dropdown>
    <span style="width: 75px">per page</span>
  </goa-block>

  <goa-spacer hspacing="fill"></goa-spacer>

  <goa-pagination
    version="2"
    id="pagination"
    itemcount="100"
    perpagecount="10"
    pagenumber="1"
  >
  </goa-pagination>
</goa-block>

Workspace

Preview not available
No React code available

Other

Use Block for general layout and spacing. Use ButtonGroup for semantically related action buttons.

Header section

Main content area

Footer section

Don't use a container for general page layout. Containers are for visual emphasis and grouping content.
All GoA Design System components are built to meet WCAG 2.2 AA standards. The following guidelines provide additional context for accessible implementation.

No accessibility-specific guidelines have been documented for this component yet.

View old component docs