Input

A single-line field where users can input and edit text.

Props

type
text | number | password | email | date | datetime-local | month | range | search | tel | time | url | week
Sets the type of the input field.
Defaults to text.
name
string
Name of input value that is received in the onChange event.
value
string
Bound to value.
autoCapitalize
on | off | none | sentences | words | characters
Controls whether and how text input is automatically capitalized as it is entered/edited by the user. This only works on mobile devices.
Defaults to off.
autoComplete
string
Specifies the autocomplete attribute for the input field.
placeholder
string
Text displayed within the input when no value is set.
leadingIcon
GoAIconType
Icon shown to the left of the text.
trailingIcon
GoAIconType
Icon shown to the right of the text.
variant
GoAInputVariant
Sets the visual style variant. 'goa' for standard GoA styling, 'bare' for minimal styling.
Defaults to goa.
disabled
boolean
Disables this input. The input will not receive focus or events. Use [attr.disabled] with [formControl].
Defaults to false.
handleTrailingIconClick
boolean
Flag that will result in an icon button component being rendered instead of an icon.
Defaults to false.
focused
boolean
Sets the cursor focus to the input.
Defaults to false.
readOnly
boolean
Makes the input readonly.
Defaults to false.
error
boolean
Sets the input to an error state.
Defaults to false.
testId
string
Sets the data-testid attribute. Used with ByTestId queries in tests.
width
string
Sets the width of the text input area.
Defaults to 30ch.
ariaLabel
string
Defines how the input 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 input.
min
string
A string value that supports any number, or an ISO 8601 format if using the date or datetime type.
max
string
A string value that supports any number, or an ISO 8601 format if using the date or datetime type.
step
number
How much a number or date should changed by.
Defaults to 1.
prefix
string
Use leadingContent slot instead.
suffix
string
Use trailingContent slot instead.
debounce
number
Debounce delay in milliseconds before firing the change event. 0 means no debounce.
Defaults to 0.
maxLength
number | null
Defines the maximum number of characters (as UTF-16 code units) the user can enter into the input.
id
string
Unique identifier for the input element. Used for label associations and accessibility.
trailingIconAriaLabel
string
Aria label for the trailing icon. Use only when the trailing icon is interactive.
textAlign
left | right
Sets the text alignment within the input field.
Defaults to left.
size
default | compact
Sets the size of the input. 'compact' reduces height for dense layouts.
Defaults to default.
version
1 | 2
The design system version for styling purposes.
Defaults to 1.
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
onKeyPress
(event: Event) => void
_keyPress
CustomEvent
onFocus
(event: Event) => void
_focus
CustomEvent
onBlur
(event: Event) => void
_blur
CustomEvent
onTrailingIconClick
(event: Event) => void
_trailingIconClick
CustomEvent

Slots

leadingContent
Named slot for content
trailingContent
Named slot for content
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>

Ask a user for an address

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

Ask a user for direct deposit information

ReactAngularWeb Components
const [bankNumber, setBankNumber] = useState("");
  const [transitNumber, setTransitNumber] = useState("");
  const [accountNumber, setAccountNumber] = useState("");
<GoabText as="h1" size="heading-l" mt="none" mb="m">Direct deposit information</GoabText>
      <GoabText as="p" mb="xl">
        Find this information on your bank's website or on your personal cheques.
        Contact your bank if you can't find this information.
      </GoabText>
      <form>
        <GoabFormItem
          label="Bank or Institution number"
          helpText="3-4 digits in length"
        >
          <GoabInput
            maxLength={4}
            name="bankNumber"
            onChange={(e) => setBankNumber(e.value)}
            value={bankNumber}
            ariaLabel="bankNumber"
            width="88px"
          />
        </GoabFormItem>
        <GoabFormItem
          label="Branch or Transit number"
          helpText="5 digits in length"
          mt="l"
        >
          <GoabInput
            maxLength={5}
            name="transitNumber"
            onChange={(e) => setTransitNumber(e.value)}
            value={transitNumber}
            ariaLabel="transitNumber"
            width="143px"
          />
        </GoabFormItem>
        <GoabFormItem
          label="Account number"
          helpText="3-12 digits in length"
          mt="l"
        >
          <GoabInput
            maxLength={12}
            name="accountNumber"
            value={accountNumber}
            onChange={(e) => setAccountNumber(e.value)}
            ariaLabel="accountNumber"
          />
        </GoabFormItem>
      </form>
      <GoabDetails heading="Where can I find this information on a personal cheque?" mt="l">
        <GoabText as="p" mb="m">
          Below is an example of where you can find the required bank information
          on a personal cheque.
        </GoabText>
        <img src="https://design.alberta.ca/images/details-demo.jpg" alt="Cheque example showing bank information locations" />
      </GoabDetails>

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

Ask a user for an Indian registration number

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

Ask a user for dollar amounts

ReactAngularWeb Components
const [tuitionAmount, setTuitionAmount] = useState("");
  const [suppliesAmount, setSuppliesAmount] = useState("");
  const [othersAmount, setOthersAmount] = useState("");
<GoabFormItem label="Tuition">
        <GoabInput
          onChange={(e) => setTuitionAmount(e.value)}
          value={tuitionAmount}
          name="tuitionAmount"
          leadingContent="$"
        />
      </GoabFormItem>
      <GoabFormItem label="Books/Supplies/Instruments" mt="l">
        <GoabInput
          onChange={(e) => setSuppliesAmount(e.value)}
          value={suppliesAmount}
          name="suppliesAmount"
          leadingContent="$"
        />
      </GoabFormItem>
      <GoabFormItem label="Other costs" mt="l">
        <GoabInput
          onChange={(e) => setOthersAmount(e.value)}
          value={othersAmount}
          name="othersAmount"
          leadingContent="$"
        />
      </GoabFormItem>

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>

Dynamically add an item to a dropdown list

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

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

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

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

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

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

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

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

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

        <GoabDivider mt="l" />

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

Filter data in a table

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

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

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

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

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

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

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

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

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

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

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

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

      {dataFiltered.length === 0 && data.length > 0 && (
        <GoabBlock mt="l" mb="l">
          No results found
        </GoabBlock>
      )}
ReactAngularWeb Components
const [addressLine1, setAddressLine1] = useState("");
  const [addressLine2, setAddressLine2] = useState("");
  const [townCity, setTownCity] = useState("");
  const [province, setProvince] = useState("");
  const [postalCode, setPostalCode] = useState("");
<GoabLink leadingIcon="arrow-back" size="small" mb="none">
        Back
      </GoabLink>

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

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

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

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

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

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

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

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>
  );
}

Reveal input based on a selection

ReactAngularWeb Components
const [contactMethod, setContactMethod] = useState("");
  const [checkboxSelection, setCheckboxSelection] = useState<string[]>([]);
<GoabFormItem
        label="How would you like to be contacted?"
        helpText="Select one option"
      >
        <GoabRadioGroup
          name="contactMethod"
          value={contactMethod}
          onChange={(e) => setContactMethod(e.value)}
        >
          <GoabRadioItem
            value="email"
            label="Email"
            reveal={
              <GoabFormItem label="Email address">
                <GoabInput name="email" onChange={() => {}} value="" />
              </GoabFormItem>
            }
          />
          <GoabRadioItem
            value="phone"
            label="Phone"
            reveal={
              <GoabFormItem label="Phone number">
                <GoabInput name="phoneNumber" onChange={() => {}} value="" />
              </GoabFormItem>
            }
          />
          <GoabRadioItem
            value="text"
            label="Text message"
            reveal={
              <GoabFormItem label="Mobile phone number">
                <GoabInput name="mobilePhoneNumber" onChange={() => {}} value="" />
              </GoabFormItem>
            }
          />
        </GoabRadioGroup>
      </GoabFormItem>

      <GoabFormItem label="How would you like to be contacted?" mt="xl">
        <GoabCheckboxList
          name="contactMethods"
          value={checkboxSelection}
          onChange={(e) => setCheckboxSelection(e.values || [])}
        >
          <GoabCheckbox
            name="email"
            text="Email"
            value="email"
            reveal={
              <GoabFormItem label="Email address">
                <GoabInput name="email" onChange={() => {}} value="" />
              </GoabFormItem>
            }
          />
          <GoabCheckbox
            name="phone"
            text="Phone"
            value="phone"
            reveal={
              <GoabFormItem label="Phone number">
                <GoabInput name="phoneNumber" onChange={() => {}} value="" />
              </GoabFormItem>
            }
          />
          <GoabCheckbox
            name="text"
            text="Text message"
            value="text"
            reveal={
              <GoabFormItem label="Mobile phone number">
                <GoabInput name="mobilePhoneNumber" onChange={() => {}} value="" />
              </GoabFormItem>
            }
          />
        </GoabCheckboxList>
      </GoabFormItem>
ReactAngularWeb Components
const [search, setSearch] = useState("");

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

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

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

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

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

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

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

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

Slotted error text in a form item

ReactAngularWeb Components
const [value, setValue] = useState("");

  const onChange = (detail: GoabInputOnChangeDetail) => {
    setValue(detail.value);
  };

  const errorMessage = (
    <>
      <i>This is </i> slotted <b>error text</b>.
    </>
  );
<GoabFormItem label="First name" error={errorMessage}>
      <GoabInput onChange={onChange} value={value} name="item" error={true} />
    </GoabFormItem>

Slotted helper text in a form item

ReactAngularWeb Components
const [value, setValue] = useState("");

  const onChange = (detail: GoabInputOnChangeDetail) => {
    setValue(detail.value);
  };

  const helpText = (
    <>
      <i>This is </i> slotted <b>help text</b>.
    </>
  );
<GoabFormItem label="First name" helpText={helpText}>
      <GoabInput onChange={onChange} value={value} name="item" />
    </GoabFormItem>

Type to create a new filter

ReactAngularWeb Components
const [typedChips, setTypedChips] = useState<string[]>([]);
  const [inputValue, setInputValue] = useState("");
<GoabFormItem label="Type to create a chip" mb="m">
        <GoabInput
          name="chipInput"
          value={inputValue}
          onChange={(e) => setInputValue(e.value.trim())}
          onKeyPress={(e) => {
            if (e.key === "Enter" && e.value.trim()) {
              setTypedChips([...typedChips, e.value.trim()]);
              setTimeout(() => setInputValue(""), 0);
            } else if (e.key === "Backspace" && !e.value.trim() && typedChips.length > 0) {
              setTypedChips(typedChips.slice(0, -1));
            }
          }}
          width="100%"
        />
      </GoabFormItem>
      <div>
        {typedChips.map((chip, index) => (
          <GoabFilterChip
            key={index}
            content={chip}
            mb="xs"
            mr="xs"
            onClick={() => setTypedChips(typedChips.filter((c) => c !== chip))}
          />
        ))}
      </div>

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.

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.

Types

Use the appropriate input type for your context to give a better experience.
Use a text area to input content longer than a single line, such as descriptions, comments, or feedback.

Content

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

Sizing

Known input length: Use fixed-width inputs for content with a specific length, such as postal code (7 characters) or year (4 characters).

Unknown input length: If you don’t know how many characters the user will need (like their name), make your text input 100% of the container.

Size text inputs based on the expected content length to help users understand what information is needed.

Capture text input from users in forms.

When to use

Use Input when you need users to enter:

  • Short text answers (names, email addresses)
  • Numbers (phone numbers, quantities)
  • Dates and times
  • Search queries

When not to use

Don’t use Input when:

  • Users need to enter multiple lines of text (use Textarea)
  • Users need to select from predefined options (use Dropdown or Radio)
  • The input requires complex formatting (consider specialized components)

Types

Input supports multiple HTML input types:

  • text - General text entry (default)
  • email - Email addresses with validation
  • password - Masked password entry
  • number - Numeric values with stepper
  • date - Date picker
  • tel - Phone numbers
  • search - Search with clear button

States

  • Default - Normal interactive state
  • Focused - When the input has keyboard focus
  • Error - When validation fails
  • Disabled - When input is not available
  • Read-only - When showing value without editing
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.