Form input group
Combines a form control with related text, buttons, or a dropdown.
On this page
This docs is LLM-friendly and available as clean Markdown.
Supported browser agents can also use WebMCP to search, read, and open these docs. Learn more
Usage
import { GlFormInput } from "gitlab-ui-react/form-input";
import {
GlFormInputGroup,
GlFormInputGroupAddon,
GlInputGroupText,
} from "gitlab-ui-react/form-input-group";<GlFormInputGroup aria-label="Username">
<GlFormInputGroupAddon position="prepend">
<GlInputGroupText id="username-prefix">@</GlInputGroupText>
</GlFormInputGroupAddon>
<GlFormInput
aria-label="Username"
aria-describedby="username-prefix" />
</GlFormInputGroup>Default
Compose a control explicitly inside GlFormInputGroup; the group does not create an input. Wrap a text prefix in GlFormInputGroupAddon and GlInputGroupText, and give the input a visible label.
import { GlFormField, GlFormFieldLabel } from "gitlab-ui-react/form-field";
import { GlFormInput } from "gitlab-ui-react/form-input";
import {
GlFormInputGroup,
GlFormInputGroupAddon,
GlInputGroupText,
} from "gitlab-ui-react/form-input-group";
export default function FormInputGroupExample() {
return (
<GlFormField className="max-w-md">
<GlFormFieldLabel
htmlFor="grouped-username"
id="grouped-username-label">
Username
</GlFormFieldLabel>
<GlFormInputGroup aria-labelledby="grouped-username-label">
<GlFormInputGroupAddon position="prepend">
<GlInputGroupText id="grouped-username-prefix">@</GlInputGroupText>
</GlFormInputGroupAddon>
<GlFormInput
aria-describedby="grouped-username-prefix"
defaultValue="NriotHrreion"
id="grouped-username" />
</GlFormInputGroup>
</GlFormField>
);
}
Text addons
Add text before or after an input to communicate a fixed prefix, suffix, or unit. Place a prepend addon before the control and an append addon after it in JSX: position selects the styling, and the group preserves child order. Keep controls and addon wrappers directly inside the group so their borders join correctly.
import { GlFormField, GlFormFieldLabel } from "gitlab-ui-react/form-field";
import { GlFormInput } from "gitlab-ui-react/form-input";
import {
GlFormInputGroup,
GlFormInputGroupAddon,
GlInputGroupText,
} from "gitlab-ui-react/form-input-group";
export default function FormInputGroupTextExample() {
return (
<GlFormField className="max-w-md">
<GlFormFieldLabel
htmlFor="grouped-repository-path"
id="grouped-repository-path-label">
Repository path
</GlFormFieldLabel>
<GlFormInputGroup aria-labelledby="grouped-repository-path-label">
<GlFormInputGroupAddon position="prepend">
<GlInputGroupText id="grouped-repository-prefix">
https://
</GlInputGroupText>
</GlFormInputGroupAddon>
<GlFormInput
aria-describedby="grouped-repository-prefix grouped-repository-suffix"
defaultValue="gitlab.com/example/repository"
id="grouped-repository-path" />
<GlFormInputGroupAddon position="append">
<GlInputGroupText id="grouped-repository-suffix">
.git
</GlInputGroupText>
</GlFormInputGroupAddon>
</GlFormInputGroup>
</GlFormField>
);
}
Button addons
Place a related action inside an addon without wrapping the button in GlInputGroupText. Set its type when it should submit or reset a form; GlButton defaults to type="button". This example uses the native form reset behavior to clear the search input.
import { GlButton } from "gitlab-ui-react/button";
import { GlFormField, GlFormFieldLabel } from "gitlab-ui-react/form-field";
import { GlFormInput } from "gitlab-ui-react/form-input";
import {
GlFormInputGroup,
GlFormInputGroupAddon,
} from "gitlab-ui-react/form-input-group";
export default function FormInputGroupButtonExample() {
return (
<form className="max-w-md">
<GlFormField>
<GlFormFieldLabel
htmlFor="grouped-search"
id="grouped-search-label">
Search projects
</GlFormFieldLabel>
<GlFormInputGroup aria-labelledby="grouped-search-label">
<GlFormInput id="grouped-search" type="search" />
<GlFormInputGroupAddon position="append">
<GlButton type="reset">Clear</GlButton>
</GlFormInputGroupAddon>
</GlFormInputGroup>
</GlFormField>
</form>
);
}
Select control
Compose GlFormSelect when the value comes from a fixed list. Render it directly inside the group; its built-in wrapper handles the joined borders and flexible width.
import { GlFormField, GlFormFieldLabel } from "gitlab-ui-react/form-field";
import {
GlFormInputGroup,
GlFormInputGroupAddon,
GlInputGroupText,
} from "gitlab-ui-react/form-input-group";
import { GlFormSelect, GlFormSelectItem } from "gitlab-ui-react/form-select";
export default function FormInputGroupSelectExample() {
return (
<GlFormField className="max-w-md">
<GlFormFieldLabel
htmlFor="grouped-member-role"
id="grouped-member-role-label">
Member role
</GlFormFieldLabel>
<GlFormInputGroup aria-labelledby="grouped-member-role-label">
<GlFormInputGroupAddon position="prepend">
<GlInputGroupText>Role</GlInputGroupText>
</GlFormInputGroupAddon>
<GlFormSelect defaultValue="developer" id="grouped-member-role">
<GlFormSelectItem value="developer">Developer</GlFormSelectItem>
<GlFormSelectItem value="maintainer">Maintainer</GlFormSelectItem>
</GlFormSelect>
</GlFormInputGroup>
</GlFormField>
);
}
Range input
A range input can use text addons to show its bounds. Set type, min, and max on GlFormInput, and keep a visible label that describes the value being adjusted.
import { GlFormField, GlFormFieldLabel } from "gitlab-ui-react/form-field";
import { GlFormInput } from "gitlab-ui-react/form-input";
import {
GlFormInputGroup,
GlFormInputGroupAddon,
GlInputGroupText,
} from "gitlab-ui-react/form-input-group";
export default function FormInputGroupRangeExample() {
return (
<GlFormField className="max-w-md">
<GlFormFieldLabel
htmlFor="grouped-progress"
id="grouped-progress-label">
Progress
</GlFormFieldLabel>
<GlFormInputGroup aria-labelledby="grouped-progress-label">
<GlFormInputGroupAddon position="prepend">
<GlInputGroupText>0</GlInputGroupText>
</GlFormInputGroupAddon>
<GlFormInput
defaultValue={50}
id="grouped-progress"
max={100}
min={0}
type="range" />
<GlFormInputGroupAddon position="append">
<GlInputGroupText>100</GlInputGroupText>
</GlFormInputGroupAddon>
</GlFormInputGroup>
</GlFormField>
);
}
States
Set readOnly, disabled, and validation state on the composed control. Set disabled separately on related actions when they should also be unavailable. A read-only input remains focusable and selectable; an invalid input needs visible feedback associated with aria-describedby.
import {
GlFormField,
GlFormFieldError,
GlFormFieldGroup,
GlFormFieldLabel,
} from "gitlab-ui-react/form-field";
import { GlButton } from "gitlab-ui-react/button";
import { GlFormInput } from "gitlab-ui-react/form-input";
import {
GlFormInputGroup,
GlFormInputGroupAddon,
GlInputGroupText,
} from "gitlab-ui-react/form-input-group";
export default function FormInputGroupStatesExample() {
return (
<GlFormFieldGroup className="max-w-md">
<GlFormField>
<GlFormFieldLabel
htmlFor="grouped-readonly-path"
id="grouped-readonly-path-label">
Repository path (read-only)
</GlFormFieldLabel>
<GlFormInputGroup aria-labelledby="grouped-readonly-path-label">
<GlFormInputGroupAddon position="prepend">
<GlInputGroupText id="grouped-readonly-prefix">
https://
</GlInputGroupText>
</GlFormInputGroupAddon>
<GlFormInput
aria-describedby="grouped-readonly-prefix"
defaultValue="gitlab.com/example/repository"
id="grouped-readonly-path"
readOnly />
</GlFormInputGroup>
</GlFormField>
<GlFormField>
<GlFormFieldLabel
htmlFor="grouped-timeout"
id="grouped-timeout-label">
Timeout
</GlFormFieldLabel>
<GlFormInputGroup aria-labelledby="grouped-timeout-label">
<GlFormInput
aria-describedby="grouped-timeout-unit grouped-timeout-error"
defaultValue={0}
id="grouped-timeout"
min={1}
state={false}
type="number" />
<GlFormInputGroupAddon position="append">
<GlInputGroupText id="grouped-timeout-unit">
seconds
</GlInputGroupText>
</GlFormInputGroupAddon>
</GlFormInputGroup>
<GlFormFieldError id="grouped-timeout-error">
Enter a timeout of at least 1 second.
</GlFormFieldError>
</GlFormField>
<GlFormField>
<GlFormFieldLabel
htmlFor="grouped-disabled-search"
id="grouped-disabled-search-label">
Search projects (disabled)
</GlFormFieldLabel>
<GlFormInputGroup aria-labelledby="grouped-disabled-search-label">
<GlFormInput disabled id="grouped-disabled-search" type="search" />
<GlFormInputGroupAddon position="append">
<GlButton disabled>Search</GlButton>
</GlFormInputGroupAddon>
</GlFormInputGroup>
</GlFormField>
</GlFormFieldGroup>
);
}
Predefined options
Compose a GlListbox inside an addon and control the input value in React to populate it from predefined options. Apply readOnly to the input when editing is unavailable, and call event.currentTarget.select() in its onClick handler to select the text. These behaviors are supplied by the composed components and event handler.
import { useState } from "react";
import { GlFormField, GlFormFieldLabel } from "gitlab-ui-react/form-field";
import { GlFormInput } from "gitlab-ui-react/form-input";
import {
GlFormInputGroup,
GlFormInputGroupAddon,
} from "gitlab-ui-react/form-input-group";
import {
GlListbox,
GlListboxContent,
GlListboxItem,
GlListboxTrigger,
type GlListboxValue,
} from "gitlab-ui-react/listbox";
export default function FormInputGroupOptionsExample() {
const [value, setValue] = useState<GlListboxValue>("https://embed.example");
return (
<GlFormField className="max-w-md">
<GlFormFieldLabel
htmlFor="grouped-selected-url"
id="grouped-selected-url-label">
Selected URL
</GlFormFieldLabel>
<GlFormInputGroup aria-labelledby="grouped-selected-url-label">
<GlFormInputGroupAddon position="prepend">
<GlListbox value={value} onValueChange={setValue}>
<GlListboxTrigger>
{value === "https://embed.example" ? "Embed" : "Share"}
</GlListboxTrigger>
<GlListboxContent aria-label="URL type">
<GlListboxItem value="https://embed.example">Embed</GlListboxItem>
<GlListboxItem value="https://share.example">Share</GlListboxItem>
</GlListboxContent>
</GlListbox>
</GlFormInputGroupAddon>
<GlFormInput
id="grouped-selected-url"
onClick={(event) => event.currentTarget.select()}
readOnly
value={value ?? ""} />
</GlFormInputGroup>
</GlFormField>
);
}
Accessibility
- Associate each input or select with a visible
GlFormFieldLabelusing matchinghtmlForandidvalues.GlInputGroupTextrenders adiv, so its text does not label a control automatically. - The root always renders
role="group". Usearia-labelledbyoraria-labelto name the group; that name does not label its individual controls. - Reference meaningful prefixes, suffixes, units, and feedback from the control with
aria-describedby. - Give every interactive addon its own accessible name. Icon-only buttons need
aria-label. - Keep JSX order consistent with visual and keyboard focus order, and preserve visible focus indicators.
- Pair
state={false}on the input with an explanation of how to fix the value; the input setsaria-invalidautomatically.
API
All three components forward supported div attributes and a ref to their rendered div. Input values, input events, validation, and disabled state belong to the composed controls.
GlFormInputGroup
Accepts children and native div attributes, except role. It renders children in the supplied order and always sets role="group".
GlFormInputGroupAddon
| Prop | Description | Default |
|---|---|---|
position |
Required. Selects prepend or append styling; it does not reorder children. |
— |
Accepts children for text, buttons, or a dropdown, plus native div attributes.
GlInputGroupText
Accepts children and native div attributes. Renders non-interactive text with the addon appearance; place it inside GlFormInputGroupAddon.