Dropdown

Present a list of options to the user to select from.

Props

name
string
Identifier for the dropdown. Should be unique.
ariaLabel
string
Defines how the selected value will be translated for the screen reader. If not specified it will fall back to the name.
ariaLabelledBy
string
The aria-labelledby attribute identifies the element(or elements) that labels the dropdown it is applied to. Normally it is the id of the label.
value
string
Stores the value of the item selected from the dropdown.
filterable
boolean
When true the dropdown will have the ability to filter options by typing into the input field.
Defaults to false.
leadingIcon
GoAIconType
Icon shown to the left of the dropdown input.
maxHeight
string
Maximum height of the dropdown menu. Non-native only.
Defaults to 276px.
placeholder
string
The text displayed for the dropdown before a selection is made. Non-native only.
width
string
Overrides the autosized menu width. Non-native only.
maxWidth
string
Sets the maximum width of the dropdown. Use a CSS unit (px, %, ch, rem, em).
disabled
boolean
Disable this control.
Defaults to false.
error
boolean
Show an error state.
Defaults to false.
native
boolean
When true will render the native select HTML element.
Defaults to false.
size
default | compact
Sets the size of the dropdown. Compact reduces height for dense layouts.
Defaults to default.
relative
string
This property has no effect and will be removed in a future version.
autoComplete
string
Specifies the autocomplete attribute for the dropdown input. Native only.
testId
string
Sets a data-testid attribute for automated testing.
mt, mr, mb, ml
none | 3xs | 2xs | xs | s | m | l | xl | 2xl | 3xl | 4xl
Apply margin to the top, right, bottom, and/or left of the component.

Events

onChange
(event: Event) => void
_change
CustomEvent
Examples

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>

Add another item in a modal

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

toggleModal() {
  this.open = !this.open;
}

updateType(event: any) {
  this.type = event.value;
}

updateName(event: any) {
  this.name = event.value;
}

updateDescription(event: any) {
  this.description = event.value;
}
<goab-button type="tertiary" leadingIcon="add" (onClick)="toggleModal()"
  >Add another item</goab-button
>
<goab-modal
  [open]="open"
  (onClose)="toggleModal()"
  heading="Add a new item"
  [actions]="actions"
>
  <p>Fill in the information to create a new item</p>
  <goab-form-item label="Type" mt="l">
    <goab-dropdown (onChange)="updateType($event)" [value]="type">
      <goab-dropdown-item value="1" label="Option 1"></goab-dropdown-item>
      <goab-dropdown-item value="2" label="Option 2"></goab-dropdown-item>
    </goab-dropdown>
  </goab-form-item>
  <goab-form-item label="Name" mt="l">
    <goab-input
      name="name"
      width="100%"
      (onChange)="updateName($event)"
      [value]="name"
    ></goab-input>
  </goab-form-item>
  <goab-form-item label="Description" mt="l">
    <goab-textarea
      name="description"
      width="100%"
      [rows]="3"
      (onChange)="updateDescription($event)"
      [value]="description"
    ></goab-textarea>
  </goab-form-item>
  <ng-template #actions>
    <goab-button-group alignment="end">
      <goab-button type="tertiary" size="compact" (onClick)="toggleModal()"
        >Cancel</goab-button
      >
      <goab-button type="primary" size="compact" (onClick)="toggleModal()"
        >Save new item</goab-button
      >
    </goab-button-group>
  </ng-template>
</goab-modal>
const modal = document.getElementById("add-item-modal");
const openBtn = document.getElementById("open-modal-btn");
const cancelBtn = document.getElementById("cancel-btn");
const saveBtn = document.getElementById("save-btn");

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

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

cancelBtn.addEventListener("_click", () => {
  modal.removeAttribute("open");
});

saveBtn.addEventListener("_click", () => {
  modal.removeAttribute("open");
});
<goa-button version="2" id="open-modal-btn" type="tertiary" leadingicon="add"
  >Add another item</goa-button
>
<goa-modal version="2" id="add-item-modal" heading="Add a new item">
  <p>Fill in the information to create a new item</p>
  <goa-form-item version="2" label="Type" mt="l">
    <goa-dropdown version="2" id="type-dropdown">
      <goa-dropdown-item value="1" label="Option 1"></goa-dropdown-item>
      <goa-dropdown-item value="2" label="Option 2"></goa-dropdown-item>
    </goa-dropdown>
  </goa-form-item>
  <goa-form-item version="2" label="Name" mt="l">
    <goa-input version="2" name="name" width="100%" id="name-input"></goa-input>
  </goa-form-item>
  <goa-form-item version="2" label="Description" mt="l">
    <goa-textarea
      version="2"
      name="description"
      width="100%"
      rows="3"
      id="description-textarea"
    ></goa-textarea>
  </goa-form-item>
  <div slot="actions">
    <goa-button-group alignment="end">
      <goa-button version="2" id="cancel-btn" type="tertiary" size="compact"
        >Cancel</goa-button
      >
      <goa-button version="2" id="save-btn" type="primary" size="compact"
        >Save new item</goa-button
      >
    </goa-button-group>
  </div>
</goa-modal>

Add and edit lots of filters

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

onClick() {
  this.open = true;
}

onClose() {
  this.open = false;
}

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

onChangeAssignedTo(e: any) {
  this.assignedTo = e.value as string;
}

closeDrawer() {
  this.open = false;
}
<goab-button (onClick)="onClick()">Filters</goab-button>
<goab-drawer
  heading="Filters"
  [open]="open"
  (onClose)="onClose()"
  position="right"
  [actions]="actions"
>
  <goab-form-item label="Entry status">
    <goab-checkbox-list name="entryStatus" (onChange)="onCheckboxChange($event)">
      <goab-checkbox name="draft" text="Draft" value="draft"></goab-checkbox>
      <goab-checkbox name="published" text="Published" value="published"></goab-checkbox>
    </goab-checkbox-list>
  </goab-form-item>
  <goab-form-item label="Assigned to - Region" mt="l">
    <goab-checkbox-list name="region" (onChange)="onCheckboxChange($event)">
      <goab-checkbox name="calgary" text="Calgary" value="calgary"></goab-checkbox>
      <goab-checkbox name="central" text="Central" value="central"></goab-checkbox>
      <goab-checkbox name="edmonton" text="Edmonton" value="edmonton"></goab-checkbox>
      <goab-checkbox name="north" text="North" value="north"></goab-checkbox>
      <goab-checkbox name="south" text="South" value="south"></goab-checkbox>
    </goab-checkbox-list>
  </goab-form-item>
  <goab-form-item label="Assigned to" mt="l">
    <goab-dropdown
      [value]="assignedTo"
      name="assignedToData"
      (onChange)="onChangeAssignedTo($event)"
    >
      <goab-dropdown-item value="1" label="Person 1"></goab-dropdown-item>
      <goab-dropdown-item value="2" label="Person 2"></goab-dropdown-item>
    </goab-dropdown>
  </goab-form-item>
  <goab-form-item label="Date taken" mt="l">
    <goab-radio-group name="dateTaken" (onChange)="radioOnChange($event)">
      <goab-radio-item value="24" label="Last 24 hours"></goab-radio-item>
      <goab-radio-item value="72" label="Last 72 hours"></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()"
        >Apply filters</goab-button
      >
      <goab-button type="tertiary" size="compact" (onClick)="closeDrawer()"
        >Cancel</goab-button
      >
    </goab-button-group>
  </ng-template>
</goab-drawer>
const drawer = document.getElementById("filters-drawer");
const openBtn = document.getElementById("open-filters-btn");
const applyBtn = document.getElementById("apply-filters-btn");
const cancelBtn = document.getElementById("cancel-btn");

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

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

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

cancelBtn.addEventListener("_click", () => {
  drawer.removeAttribute("open");
});
<goa-button version="2" id="open-filters-btn">Filters</goa-button>
<goa-drawer version="2" id="filters-drawer" heading="Filters" position="right">
  <goa-form-item version="2" label="Entry status">
    <goa-checkbox-list name="entryStatus">
      <goa-checkbox version="2" name="draft" text="Draft" value="draft"></goa-checkbox>
      <goa-checkbox
        version="2"
        name="published"
        text="Published"
        value="published"
      ></goa-checkbox>
    </goa-checkbox-list>
  </goa-form-item>
  <goa-form-item version="2" label="Assigned to - Region" mt="l">
    <goa-checkbox-list name="region">
      <goa-checkbox
        version="2"
        name="calgary"
        text="Calgary"
        value="calgary"
      ></goa-checkbox>
      <goa-checkbox
        version="2"
        name="central"
        text="Central"
        value="central"
      ></goa-checkbox>
      <goa-checkbox
        version="2"
        name="edmonton"
        text="Edmonton"
        value="edmonton"
      ></goa-checkbox>
      <goa-checkbox version="2" name="north" text="North" value="north"></goa-checkbox>
      <goa-checkbox version="2" name="south" text="South" value="south"></goa-checkbox>
    </goa-checkbox-list>
  </goa-form-item>
  <goa-form-item version="2" label="Assigned to" mt="l">
    <goa-dropdown version="2" name="assignedTo">
      <goa-dropdown-item value="1" label="Person 1"></goa-dropdown-item>
      <goa-dropdown-item value="2" label="Person 2"></goa-dropdown-item>
    </goa-dropdown>
  </goa-form-item>
  <goa-form-item version="2" label="Date taken" mt="l">
    <goa-radio-group version="2" name="dateTaken">
      <goa-radio-item value="24" label="Last 24 hours"></goa-radio-item>
      <goa-radio-item value="72" label="Last 72 hours"></goa-radio-item>
    </goa-radio-group>
  </goa-form-item>
  <div slot="actions">
    <goa-button-group alignment="start">
      <goa-button version="2" id="apply-filters-btn" type="primary" size="compact"
        >Apply filters</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>

Dynamically add an item to a dropdown list

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

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

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

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

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

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

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

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

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

<GoabDivider mt="l" />

<GoabFormItem mt="l" label="All items">
  <div style={{ width: isReset ? "320px" : "auto" }}>
    <GoabDropdown
      key={tasks.length}
      onChange={(event: GoabDropdownOnChangeDetail) =>
        setSelectedTask(event.value as string)
      }
      value={selectedTask}
      name="selectedTask"
    >
      {tasks.map((task) => (
        <GoabDropdownItem
          key={task.value}
          value={task.value}
          mountType={task.mount}
          label={task.label}
        />
      ))}
    </GoabDropdown>
  </div>
</GoabFormItem>
defaultTasks: Task[] = [
  { label: "Finish Report", value: "finish-report", mount: "append" },
  { label: "Attend Meeting", value: "attend-meeting", mount: "append" },
  { label: "Reply Emails", value: "reply-emails", mount: "append" },
];

tasks: Task[] = [...this.defaultTasks];
newTask = "";
mountType: GoabDropdownItemMountType = "append";
selectedTask = "";
taskError = false;
renderTrigger = true;

onMountTypeChange(event: GoabRadioGroupOnChangeDetail): void {
  this.mountType = event.value as GoabDropdownItemMountType;
}

onNewTaskChange(event: GoabInputOnChangeDetail): void {
  this.newTask = event.value;
  this.taskError = false;
}

onSelectedTaskChange(event: GoabDropdownOnChangeDetail): void {
  this.selectedTask = event.value as string;
}

addTask(): void {
  if (this.newTask === "") {
    this.taskError = true;
    return;
  }
  this.taskError = false;

  const task: Task = {
    label: this.newTask,
    value: this.newTask.toLowerCase().replace(" ", "-"),
    mount: this.mountType,
  };
  this.tasks =
    this.mountType === "prepend" ? [task, ...this.tasks] : [...this.tasks, task];
  this.newTask = "";
}

reset(): void {
  this.newTask = "";
  this.selectedTask = "";
  this.taskError = false;
  this.tasks = [...this.defaultTasks];
  this.forceRerender();
}

forceRerender(): void {
  this.renderTrigger = false;
  setTimeout(() => {
    this.renderTrigger = true;
  }, 0);
}

trackByFn(index: number, item: Task): string {
  return item.value;
}
<goab-form-item
  requirement="required"
  label="Name of item"
  [error]="taskError ? 'Please enter item name' : undefined"
  helpText="Add an item to the dropdown list below"
>
  <goab-input name="item" [value]="newTask" (onChange)="onNewTaskChange($event)">
  </goab-input>
</goab-form-item>

<goab-form-item mt="l" label="Add to">
  <goab-radio-group
    name="mountType"
    [value]="mountType"
    orientation="horizontal"
    (onChange)="onMountTypeChange($event)"
  >
    <goab-radio-item value="prepend" label="Start"></goab-radio-item>
    <goab-radio-item value="append" label="End"></goab-radio-item>
  </goab-radio-group>
</goab-form-item>

<goab-button-group alignment="start" gap="relaxed" mt="l">
  <goab-button type="primary" (onClick)="addTask()"> Add new item </goab-button>
  <goab-button type="tertiary" (onClick)="reset()"> Reset list </goab-button>
</goab-button-group>

<goab-divider mt="l"></goab-divider>

<goab-form-item mt="l" label="All items">
  <ng-container *ngIf="renderTrigger">
    <goab-dropdown
      [value]="selectedTask"
      name="selectedTask"
      (onChange)="onSelectedTaskChange($event)"
    >
      @for (task of tasks; track task.value) {
      <goab-dropdown-item
        [value]="task.value"
        [mountType]="task.mount"
        [label]="task.label"
      >
      </goab-dropdown-item>
      }
    </goab-dropdown>
  </ng-container>
</goab-form-item>
const itemInput = document.getElementById("item-input");
const itemFormItem = document.getElementById("item-form-item");
const mountTypeGroup = document.getElementById("mount-type");
const addBtn = document.getElementById("add-btn");
const resetBtn = document.getElementById("reset-btn");
const dropdown = document.getElementById("task-dropdown");

let mountType = "append";
let newTask = "";

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

mountTypeGroup.addEventListener("_change", (e) => {
  mountType = e.detail.value;
});

itemInput.addEventListener("_change", (e) => {
  newTask = e.detail.value;
  itemFormItem.removeAttribute("error");
});

addBtn.addEventListener("_click", () => {
  if (newTask === "") {
    itemFormItem.setAttribute("error", "Please enter item name");
    return;
  }

  const newItem = document.createElement("goa-dropdown-item");
  newItem.setAttribute("value", newTask.toLowerCase().replace(" ", "-"));
  newItem.setAttribute("label", newTask);
  newItem.setAttribute("mount", mountType);
  dropdown.appendChild(newItem);

  itemInput.value = "";
  newTask = "";
});

resetBtn.addEventListener("_click", () => {
  dropdown.innerHTML = "";
  defaultItems.forEach((item) => {
    const dropdownItem = document.createElement("goa-dropdown-item");
    dropdownItem.setAttribute("value", item.value);
    dropdownItem.setAttribute("label", item.label);
    dropdown.appendChild(dropdownItem);
  });
  itemInput.value = "";
  newTask = "";
  itemFormItem.removeAttribute("error");
});
<goa-form-item
  version="2"
  id="item-form-item"
  requirement="required"
  label="Name of item"
  helptext="Add an item to the dropdown list below"
>
  <goa-input version="2" id="item-input" name="item"></goa-input>
</goa-form-item>

<goa-form-item version="2" mt="l" label="Add to">
  <goa-radio-group
    version="2"
    id="mount-type"
    name="mountType"
    value="append"
    orientation="horizontal"
  >
    <goa-radio-item value="prepend" label="Start"></goa-radio-item>
    <goa-radio-item value="append" label="End"></goa-radio-item>
  </goa-radio-group>
</goa-form-item>

<goa-button-group alignment="start" gap="relaxed" mt="l">
  <goa-button version="2" id="add-btn" type="primary">Add new item</goa-button>
  <goa-button version="2" id="reset-btn" type="tertiary">Reset list</goa-button>
</goa-button-group>

<goa-divider mt="l"></goa-divider>

<goa-form-item version="2" mt="l" label="All items">
  <goa-dropdown version="2" id="task-dropdown" name="selectedTask">
    <goa-dropdown-item value="finish-report" label="Finish Report"></goa-dropdown-item>
    <goa-dropdown-item value="attend-meeting" label="Attend Meeting"></goa-dropdown-item>
    <goa-dropdown-item value="reply-emails" label="Reply Emails"></goa-dropdown-item>
  </goa-dropdown>
</goa-form-item>

Dynamically change items in a dropdown list

const [children, setChildren] = useState<string[]>([]);
const parents = ["All", "Big", "Small"];
const childrenAll = ["Bus", "Elephant", "Key", "Pen", "Watch", "Truck"];
const childrenBig = ["Elephant", "Truck", "Bus"];
const childrenSmall = ["Key", "Pen", "Watch"];

const loadItems = (value: string) => {
  if (value === "All") setChildren(childrenAll);
  else if (value === "Big") setChildren(childrenBig);
  else setChildren(childrenSmall);
};

const logSelection = () => {
  console.log("Item selected");
};
<GoabFormItem
  label="Size"
  requirement="optional"
  helpText="Choose the size to change the list below"
>
  <GoabDropdown
    name="parent"
    placeholder="Select a value"
    onChange={(event: GoabDropdownOnChangeDetail) =>
      loadItems(event.value as string)
    }
  >
    {parents.map((parent) => (
      <GoabDropdownItem key={parent} value={parent} label={parent} />
    ))}
  </GoabDropdown>
</GoabFormItem>

<GoabFormItem label="Items" requirement="optional" mt="xl">
  <GoabDropdown
    name="children"
    placeholder="Select a value"
    onChange={logSelection}
  >
    {children.map((child) => (
      <GoabDropdownItem key={child} value={child} label={child} mountType="reset" />
    ))}
  </GoabDropdown>
</GoabFormItem>
<div [formGroup]="changeForm" style="padding: 40px">
  <goab-form-item
    label="Size"
    requirement="optional"
    helpText="Choose the size to change the list below"
  >
    <goab-dropdown
      formControlName="parentDropdown"
      placeholder="Select a value"
      name="parent"
    >
      @for (parent of parents; track parent) {
      <goab-dropdown-item [value]="parent" [label]="parent" />
      }
    </goab-dropdown>
  </goab-form-item>

  <goab-form-item label="Items" requirement="optional" mt="xl">
    <goab-dropdown
      formControlName="childDropdown"
      placeholder="Select a value"
      name="children"
    >
      <ng-container *ngIf="children.length > 0">
        @for (child of children; track child) {
        <goab-dropdown-item [value]="child" [label]="child" [mountType]="'reset'" />
        }
      </ng-container>
    </goab-dropdown>
  </goab-form-item>
</div>
const parentDropdown = document.getElementById("parent-dropdown");
const childDropdown = document.getElementById("child-dropdown");

const childrenAll = ["Bus", "Elephant", "Key", "Pen", "Watch", "Truck"];
const childrenBig = ["Elephant", "Truck", "Bus"];
const childrenSmall = ["Key", "Pen", "Watch"];

function updateChildren(items) {
  childDropdown.innerHTML = "";
  items.forEach((item) => {
    const dropdownItem = document.createElement("goa-dropdown-item");
    dropdownItem.setAttribute("value", item);
    dropdownItem.setAttribute("label", item);
    dropdownItem.setAttribute("mount", "reset");
    childDropdown.appendChild(dropdownItem);
  });
}

parentDropdown.addEventListener("_change", (e) => {
  const value = e.detail.value;
  if (value === "All") updateChildren(childrenAll);
  else if (value === "Big") updateChildren(childrenBig);
  else updateChildren(childrenSmall);
});

childDropdown.addEventListener("_change", () => {
  console.log("Item selected");
});
<div style="padding: 40px">
  <goa-form-item
    version="2"
    label="Size"
    requirement="optional"
    helptext="Choose the size to change the list below"
  >
    <goa-dropdown
      version="2"
      id="parent-dropdown"
      placeholder="Select a value"
      name="parent"
    >
      <goa-dropdown-item value="All" label="All"></goa-dropdown-item>
      <goa-dropdown-item value="Big" label="Big"></goa-dropdown-item>
      <goa-dropdown-item value="Small" label="Small"></goa-dropdown-item>
    </goa-dropdown>
  </goa-form-item>

  <goa-form-item version="2" label="Items" requirement="optional" mt="xl">
    <goa-dropdown
      version="2"
      id="child-dropdown"
      placeholder="Select a value"
      name="children"
    >
    </goa-dropdown>
  </goa-form-item>
</div>

Filter a list using a push drawer

const [open, setOpen] = useState(false);
<div style={{ display: "flex", minHeight: "480px" }}>
  <div style={{ flex: 1, minWidth: 0 }}>
    <div
      style={{
        display: "flex",
        alignItems: "center",
        gap: "1rem",
        marginBottom: "1rem",
      }}
    >
      <h3 style={{ flex: 1, margin: 0 }}>All cases</h3>
      {!open && (
        <GoabButton
          type="secondary"
          size="compact"
          leadingIcon="filter"
          onClick={() => setOpen(true)}
        >
          Filters
        </GoabButton>
      )}
    </div>

    <GoabTable width="100%">
      <table width="100%">
        <thead>
          <tr>
            <th>Status</th>
            <th>Name</th>
            <th>File number</th>
            <th>Act</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>
              <GoabBadge type="success" content="Completed" />
            </td>
            <td>Gilbert Barton</td>
            <td>24567-9876</td>
            <td>Traffic safety act</td>
          </tr>
          <tr>
            <td>
              <GoabBadge type="information" content="New" />
            </td>
            <td>Brynn Hurley</td>
            <td>98765-3456</td>
            <td>Trespass to premises act</td>
          </tr>
          <tr>
            <td>
              <GoabBadge type="default" content="In review" />
            </td>
            <td>Marco Silva</td>
            <td>34521-7890</td>
            <td>Gaming, liquor, and cannabis act</td>
          </tr>
          <tr>
            <td>
              <GoabBadge type="success" content="Completed" />
            </td>
            <td>Dana Chen</td>
            <td>55123-4567</td>
            <td>Traffic safety act</td>
          </tr>
          <tr>
            <td>
              <GoabBadge type="information" content="New" />
            </td>
            <td>Amira Hassan</td>
            <td>67890-1234</td>
            <td>Trespass to premises act</td>
          </tr>
        </tbody>
      </table>
    </GoabTable>
  </div>

  <GoabPushDrawer
    heading="Filters"
    width="260px"
    open={open}
    onClose={() => setOpen(false)}
  >
    <GoabFormItem label="Act">
      <GoabCheckboxList name="act" onChange={() => {}}>
        <GoabCheckbox name="traffic" text="Traffic safety act" size="compact" />
        <GoabCheckbox
          name="gaming"
          text="Gaming, liquor, and cannabis act"
          size="compact"
        />
        <GoabCheckbox
          name="trespass"
          text="Trespass to premises act"
          size="compact"
        />
      </GoabCheckboxList>
    </GoabFormItem>
    <GoabFormItem label="Status" mt="l">
      <GoabDropdown name="status" onChange={() => {}} value="" size="compact">
        <GoabDropdownItem value="" label="All statuses" />
        <GoabDropdownItem value="new" label="New" />
        <GoabDropdownItem value="in-review" label="In review" />
        <GoabDropdownItem value="completed" label="Completed" />
      </GoabDropdown>
    </GoabFormItem>
  </GoabPushDrawer>
</div>
open = false;

openFilters(): void {
  this.open = true;
}

closeFilters(): void {
  this.open = false;
}

onCheckboxChange(event: GoabCheckboxOnChangeDetail): void {
  console.log(event);
}

onDropdownChange(event: GoabDropdownOnChangeDetail): void {
  console.log(event);
}
<div style="display: flex; min-height: 480px">
  <div style="flex: 1; min-width: 0">
    <div style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1rem">
      <h3 style="flex: 1; margin: 0">All cases</h3>
      @if (!open) {
      <goab-button
        type="secondary"
        size="compact"
        leadingIcon="filter"
        (onClick)="openFilters()"
        >Filters</goab-button
      >
      }
    </div>

    <goab-table width="100%">
      <table width="100%">
        <thead>
          <tr>
            <th>Status</th>
            <th>Name</th>
            <th>File number</th>
            <th>Act</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td><goab-badge type="success" content="Completed"></goab-badge></td>
            <td>Gilbert Barton</td>
            <td>24567-9876</td>
            <td>Traffic safety act</td>
          </tr>
          <tr>
            <td><goab-badge type="information" content="New"></goab-badge></td>
            <td>Brynn Hurley</td>
            <td>98765-3456</td>
            <td>Trespass to premises act</td>
          </tr>
          <tr>
            <td><goab-badge type="default" content="In review"></goab-badge></td>
            <td>Marco Silva</td>
            <td>34521-7890</td>
            <td>Gaming, liquor, and cannabis act</td>
          </tr>
          <tr>
            <td><goab-badge type="success" content="Completed"></goab-badge></td>
            <td>Dana Chen</td>
            <td>55123-4567</td>
            <td>Traffic safety act</td>
          </tr>
          <tr>
            <td><goab-badge type="information" content="New"></goab-badge></td>
            <td>Amira Hassan</td>
            <td>67890-1234</td>
            <td>Trespass to premises act</td>
          </tr>
        </tbody>
      </table>
    </goab-table>
  </div>

  <goab-push-drawer
    heading="Filters"
    width="260px"
    [open]="open"
    (onClose)="closeFilters()"
  >
    <goab-form-item label="Act">
      <goab-checkbox-list name="act" (onChange)="onCheckboxChange($event)">
        <goab-checkbox
          name="traffic"
          text="Traffic safety act"
          size="compact"
        ></goab-checkbox>
        <goab-checkbox
          name="gaming"
          text="Gaming, liquor, and cannabis act"
          size="compact"
        ></goab-checkbox>
        <goab-checkbox
          name="trespass"
          text="Trespass to premises act"
          size="compact"
        ></goab-checkbox>
      </goab-checkbox-list>
    </goab-form-item>
    <goab-form-item label="Status" mt="l">
      <goab-dropdown
        name="status"
        (onChange)="onDropdownChange($event)"
        value=""
        size="compact"
      >
        <goab-dropdown-item value="" label="All statuses"></goab-dropdown-item>
        <goab-dropdown-item value="new" label="New"></goab-dropdown-item>
        <goab-dropdown-item value="in-review" label="In review"></goab-dropdown-item>
        <goab-dropdown-item value="completed" label="Completed"></goab-dropdown-item>
      </goab-dropdown>
    </goab-form-item>
  </goab-push-drawer>
</div>
const filtersDrawer = document.getElementById("filters-drawer");
const openFiltersBtn = document.getElementById("open-filters-btn");

openFiltersBtn.addEventListener("_click", () => {
  filtersDrawer.setAttribute("open", "true");
  openFiltersBtn.style.display = "none";
});

filtersDrawer.addEventListener("_close", () => {
  filtersDrawer.removeAttribute("open");
  openFiltersBtn.style.display = "";
});
<div style="display: flex; min-height: 480px">
  <div style="flex: 1; min-width: 0">
    <div style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1rem">
      <h3 style="flex: 1; margin: 0">All cases</h3>
      <goa-button
        version="2"
        id="open-filters-btn"
        type="secondary"
        size="compact"
        leadingicon="filter"
        >Filters</goa-button
      >
    </div>

    <goa-table version="2" width="100%">
      <table width="100%">
        <thead>
          <tr>
            <th>Status</th>
            <th>Name</th>
            <th>File number</th>
            <th>Act</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>
              <goa-badge version="2" type="success" content="Completed"></goa-badge>
            </td>
            <td>Gilbert Barton</td>
            <td>24567-9876</td>
            <td>Traffic safety act</td>
          </tr>
          <tr>
            <td><goa-badge version="2" type="information" content="New"></goa-badge></td>
            <td>Brynn Hurley</td>
            <td>98765-3456</td>
            <td>Trespass to premises act</td>
          </tr>
          <tr>
            <td>
              <goa-badge version="2" type="default" content="In review"></goa-badge>
            </td>
            <td>Marco Silva</td>
            <td>34521-7890</td>
            <td>Gaming, liquor, and cannabis act</td>
          </tr>
          <tr>
            <td>
              <goa-badge version="2" type="success" content="Completed"></goa-badge>
            </td>
            <td>Dana Chen</td>
            <td>55123-4567</td>
            <td>Traffic safety act</td>
          </tr>
          <tr>
            <td><goa-badge version="2" type="information" content="New"></goa-badge></td>
            <td>Amira Hassan</td>
            <td>67890-1234</td>
            <td>Trespass to premises act</td>
          </tr>
        </tbody>
      </table>
    </goa-table>
  </div>

  <goa-push-drawer version="2" id="filters-drawer" heading="Filters" width="260px">
    <goa-form-item version="2" label="Act">
      <goa-checkbox-list name="act">
        <goa-checkbox
          version="2"
          name="traffic"
          text="Traffic safety act"
          size="compact"
        ></goa-checkbox>
        <goa-checkbox
          version="2"
          name="gaming"
          text="Gaming, liquor, and cannabis act"
          size="compact"
        ></goa-checkbox>
        <goa-checkbox
          version="2"
          name="trespass"
          text="Trespass to premises act"
          size="compact"
        ></goa-checkbox>
      </goa-checkbox-list>
    </goa-form-item>
    <goa-form-item version="2" label="Status" mt="l">
      <goa-dropdown version="2" name="status" size="compact">
        <goa-dropdown-item value="" label="All statuses"></goa-dropdown-item>
        <goa-dropdown-item value="new" label="New"></goa-dropdown-item>
        <goa-dropdown-item value="in-review" label="In review"></goa-dropdown-item>
        <goa-dropdown-item value="completed" label="Completed"></goa-dropdown-item>
      </goa-dropdown>
    </goa-form-item>
  </goa-push-drawer>
</div>
const [addressLine1, setAddressLine1] = useState("");
const [addressLine2, setAddressLine2] = useState("");
const [townCity, setTownCity] = useState("");
const [province, setProvince] = useState("");
const [postalCode, setPostalCode] = useState("");
<GoabLink leadingIcon="arrow-back" size="small" mb="none">
  Back
</GoabLink>

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

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

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

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

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

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

<GoabButton type="submit" mt="2xl">
  Save and continue
</GoabButton>
addressLine1 = "";
addressLine2 = "";
townCity = "";
province = "";
postalCode = "";

onAddressLine1Change(value: string): void {
  this.addressLine1 = value;
}

onAddressLine2Change(value: string): void {
  this.addressLine2 = value;
}

onTownCityChange(value: string): void {
  this.townCity = value;
}

onProvinceChange(value: string): void {
  this.province = value;
}

onPostalCodeChange(value: string): void {
  this.postalCode = value;
}

onSubmit(): void {
  console.log("Form submitted");
}
<goab-link leadingIcon="arrow-back" size="small" mb="none"> Back </goab-link>

<goab-text tag="h2" mt="xl" mb="m">Your address</goab-text>
<goab-text mt="none" mb="xl">This is the home address of the person applying</goab-text>

<goab-form-item label="Address line 1">
  <goab-input
    (onChange)="onAddressLine1Change($event)"
    [value]="addressLine1"
    name="address-line-1"
    ariaLabel="Address line 1"
    width="100%"
  >
  </goab-input>
</goab-form-item>

<goab-form-item label="Address line 2" mt="l">
  <goab-input
    (onChange)="onAddressLine2Change($event)"
    [value]="addressLine2"
    name="address-line-2"
    ariaLabel="Address line 2"
    width="100%"
  >
  </goab-input>
</goab-form-item>

<goab-form-item label="Town or city" mt="l">
  <goab-input
    (onChange)="onTownCityChange($event)"
    [value]="townCity"
    name="town-city"
    ariaLabel="Town or city name"
    width="460px"
  >
  </goab-input>
</goab-form-item>

<goab-form-item label="Province or territory" mt="l" id="provinceLabel">
  <goab-dropdown
    (onChange)="onProvinceChange($event)"
    [value]="province"
    name="province-territory"
    ariaLabelledBy="provinceLabel"
  >
    <goab-dropdown-item value="AB" label="Alberta"></goab-dropdown-item>
    <goab-dropdown-item value="BC" label="British Columbia"></goab-dropdown-item>
    <goab-dropdown-item value="MB" label="Manitoba"></goab-dropdown-item>
    <goab-dropdown-item value="NB" label="New Brunswick"></goab-dropdown-item>
    <goab-dropdown-item value="NL" label="Newfoundland and Labrador"></goab-dropdown-item>
    <goab-dropdown-item value="NS" label="Nova Scotia"></goab-dropdown-item>
    <goab-dropdown-item value="ON" label="Ontario"></goab-dropdown-item>
    <goab-dropdown-item value="PE" label="Prince Edward Island"></goab-dropdown-item>
    <goab-dropdown-item value="QC" label="Quebec"></goab-dropdown-item>
    <goab-dropdown-item value="SK" label="Saskatchewan"></goab-dropdown-item>
    <goab-dropdown-item value="NT" label="Northwest Territories"></goab-dropdown-item>
    <goab-dropdown-item value="NU" label="Nunavut"></goab-dropdown-item>
    <goab-dropdown-item value="YT" label="Yukon"></goab-dropdown-item>
  </goab-dropdown>
</goab-form-item>

<goab-form-item label="Postal code" mt="l">
  <goab-input
    (onChange)="onPostalCodeChange($event)"
    [value]="postalCode"
    name="postal-code"
    width="105px"
  >
  </goab-input>
</goab-form-item>

<goab-button type="submit" mt="2xl" (onClick)="onSubmit()">
  Save and continue
</goab-button>
document.getElementById("address-line-1").addEventListener("_change", (e) => {
  console.log("Address line 1:", e.detail.value);
});

document.getElementById("province-territory").addEventListener("_change", (e) => {
  console.log("Province:", e.detail.value);
});

document.getElementById("submit-btn").addEventListener("_click", () => {
  console.log("Form submitted");
});
<goa-link leadingicon="arrow-back" size="small" mb="none"> Back </goa-link>

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

<goa-form-item version="2" label="Address line 1">
  <goa-input
    version="2"
    id="address-line-1"
    name="address-line-1"
    aria-label="Address line 1"
    width="100%"
  >
  </goa-input>
</goa-form-item>

<goa-form-item version="2" label="Address line 2" mt="l">
  <goa-input
    version="2"
    id="address-line-2"
    name="address-line-2"
    aria-label="Address line 2"
    width="100%"
  >
  </goa-input>
</goa-form-item>

<goa-form-item version="2" label="Town or city" mt="l">
  <goa-input
    version="2"
    id="town-city"
    name="town-city"
    aria-label="Town or city name"
    width="460px"
  >
  </goa-input>
</goa-form-item>

<goa-form-item version="2" label="Province or territory" mt="l" id="provinceLabel">
  <goa-dropdown
    version="2"
    id="province-territory"
    name="province-territory"
    aria-labelledby="provinceLabel"
  >
    <goa-dropdown-item value="AB" label="Alberta"></goa-dropdown-item>
    <goa-dropdown-item value="BC" label="British Columbia"></goa-dropdown-item>
    <goa-dropdown-item value="MB" label="Manitoba"></goa-dropdown-item>
    <goa-dropdown-item value="NB" label="New Brunswick"></goa-dropdown-item>
    <goa-dropdown-item value="NL" label="Newfoundland and Labrador"></goa-dropdown-item>
    <goa-dropdown-item value="NS" label="Nova Scotia"></goa-dropdown-item>
    <goa-dropdown-item value="ON" label="Ontario"></goa-dropdown-item>
    <goa-dropdown-item value="PE" label="Prince Edward Island"></goa-dropdown-item>
    <goa-dropdown-item value="QC" label="Quebec"></goa-dropdown-item>
    <goa-dropdown-item value="SK" label="Saskatchewan"></goa-dropdown-item>
    <goa-dropdown-item value="NT" label="Northwest Territories"></goa-dropdown-item>
    <goa-dropdown-item value="NU" label="Nunavut"></goa-dropdown-item>
    <goa-dropdown-item value="YT" label="Yukon"></goa-dropdown-item>
  </goa-dropdown>
</goa-form-item>

<goa-form-item version="2" label="Postal code" mt="l">
  <goa-input version="2" id="postal-code" name="postal-code" width="105px"> </goa-input>
</goa-form-item>

<goa-button version="2" type="submit" mt="2xl" id="submit-btn">
  Save and continue
</goa-button>

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>

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>

States

Submit

When you must disable a button or input:

  • Provide nearby text explaining what needs to happen first
  • Consider showing the element enabled with validation on submit instead
  • Use aria-describedby to link the disabled element to explanatory text
Don't disable buttons or inputs without explaining why. Disabled controls can be confusing and users may not understand why they can't interact with an element.

Sizing

Define dropdown widths based on the widest dropdown in the form.
Use the default width for dropdowns. The dropdown automatically sets its width based on the length of the options.

Positioning

Don't allow the dropdown menu to hide below the viewport.

Content

Don't truncate labels. Longer labels should wrap to the next line.

Placeholder text disappears when users start typing, leaving them without context for what the field is asking for.

Always use a visible label above or beside the input field. Placeholder text can provide an example of the expected format, but should never be the only indication of what information is needed.

Don't use placeholder text as a label

Other

The form item automatically associates the label with the input for screen readers, ensuring your form is accessible.

Use a form item wrapper on all inputs to add a label, helper text, error message, and more.
All GoA Design System components are built to meet WCAG 2.2 AA standards. The following guidelines provide additional context for accessible implementation.

Screen Readers

When a Dropdown is not wrapped in a FormItem, set ariaLabel to provide an accessible name. Without it, screen readers won't be able to identify the dropdown.
View old component docs