Button group

Display multiple related actions stacked or in a horizontal row to help with arrangement and spacing.

Props

alignment
start | end | center
Positions the button group in the page layout.
Defaults to start.
gap
relaxed | compact
Sets the spacing between buttons in the button group.
Defaults to relaxed.
testId
string
Sets the data-testid attribute. Used with ByTestId queries in tests.
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

Add another item in a modal

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

Add a record using a drawer

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

Add and edit lots of filters

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

Ask a user for an address

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

Button with Icon

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

When using icons in buttons, the button text provides the accessible name. The icon is decorative and should be hidden from screen readers with aria-hidden.

Confirm a change

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

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

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

Confirm a destructive action

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

Confirm before navigating away

ReactAngularWeb Components
const [open, setOpen] = useState(false);

  const handleChangeRoute = () => {
    setOpen(false);
    // In a real app, you would use your router's navigate function
    // setTimeout(() => navigate("/some-path"), 300);
    console.log("Navigating to new route...");
  };
<GoabButton onClick={() => setOpen(true)}>Open</GoabButton>
      <GoabModal
        heading="Are you sure you want to change route?"
        open={open}
        onClose={() => setOpen(false)}
        actions={
          <GoabButtonGroup alignment="end">
            <GoabButton type="secondary" size="compact" onClick={() => setOpen(false)}>
              Cancel
            </GoabButton>
            <GoabButton type="primary" size="compact" onClick={handleChangeRoute}>
              Change route
            </GoabButton>
          </GoabButtonGroup>
        }
      />

Confirm that an application was submitted

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

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

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

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

Disabled button with a required field

ReactAngularWeb Components
const [inputValue, setInputValue] = useState("");

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

  const handleConfirm = () => {
    // Handle form submission
    console.log("Form submitted with:", inputValue);
  };

  const handleCancel = () => {
    // Handle cancellation
    setInputValue("");
  };
<form>
      <GoabFormItem label="Name" requirement="required">
        <GoabInput
          name="input"
          type="text"
          onChange={handleInputChange}
          value={inputValue}
          width="100%"
        />
      </GoabFormItem>

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

Give context before asking a long answer question

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

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

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

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

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

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

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

Question page

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

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

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

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

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

Reset date picker field

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

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

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

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

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

Require user action before continuing

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

Review page

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

Show a label on an icon only button

ReactAngularWeb Components
<GoabButtonGroup alignment="start">
      <GoabTooltip content="Edit">
        <GoabIconButton icon="pencil" ariaLabel="Edit" />
      </GoabTooltip>
      <GoabTooltip content="Alerts">
        <GoabIconButton icon="notifications" ariaLabel="Alerts" />
      </GoabTooltip>
      <GoabTooltip content="Settings">
        <GoabIconButton icon="settings" ariaLabel="Settings" />
      </GoabTooltip>
    </GoabButtonGroup>

Warn a user of a deadline

ReactAngularWeb Components
const [open, setOpen] = useState(false);
<GoabButton type="secondary" onClick={() => setOpen(true)}>
        Save for later
      </GoabButton>
      <GoabModal
        heading="Complete submission prior to 1PM"
        calloutVariant="important"
        open={open}
        onClose={() => setOpen(false)}
        actions={
          <GoabButtonGroup alignment="end">
            <GoabButton type="primary" onClick={() => setOpen(false)}>
              I understand
            </GoabButton>
          </GoabButtonGroup>
        }
      >
        <p>
          You've selected to adjourn a matter that is required to appear today. This Calgary court
          location does not accept adjournment requests past 1PM MST. Please submit your
          adjournment request as soon as possible.
        </p>
      </GoabModal>
  );
}

Sizing

CancelSave
Don't stack standard and full width buttons.
SaveCancel
Don't use different button sizes in the same area to emphasize hierarchy.
SaveCancel
Use full width buttons on mobile.

Positioning

SubmitEditSaveCopyDraft
Don't group more than 3 actions together. Consider using an overflow menu for additional options.
SubmitCancel
Use a button group when putting multiple buttons together.

Types

  • Primary - If there is only one button on a page, it should be a primary button. For citizen facing applications, generally there should only be one primary button on a page.
  • Secondary - Use secondary buttons for less important actions on a page. Often paired with a primary action as a secondary action.
  • Tertiary - Use tertiary buttons for links that should function like a button, such as “edit” or “cancel” in applications. It’s okay to use more than one tertiary button on a page.
SaveCancel
Use a primary button for main actions and a secondary button for less important actions.
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.