InputGroup
An input or textarea with icons, text, shortcuts or buttons attached inside its border.
An input group puts things inside the border of a text field: a search icon, a fixed prefix such as
https://, a unit, a keyboard shortcut, or a button that acts on the value, such as copy or clear.
The group draws one border and one focus state for all of it. For a field with a label, put the
group in a Field.
// apps/docs/examples/ui/input-group.tsx'use client';
import {useEffect, useRef, useState} from 'react';import {CheckIcon, CopyIcon, SearchIcon} from 'lucide-react';
import { Field, FieldLabel,} from '@workspace/active-ui/components/primitives/field';import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea,} from '@workspace/active-ui/components/primitives/input-group';import {Kbd} from '@workspace/active-ui/components/primitives/kbd';
const LINK = 'https://example.com/schemes/ps-2026';
/** * An input with something attached: an icon and a shortcut, a fixed prefix * and suffix, a button that acts on the value, and a textarea with a footer. * Clicking an addon that is not a button focuses the input. The shortcut * shown in the search field works: `/` focuses it, unless you are typing * in another field. */export default function InputGroupExample() { const [copied, setCopied] = useState(false); const [message, setMessage] = useState(''); const search = useRef<HTMLInputElement>(null); useEffect(() => { const onKey = (event: KeyboardEvent) => { const target = event.target as HTMLElement; if (event.key !== '/' || target.closest('input, textarea, select')) { return; } event.preventDefault(); search.current?.focus(); }; document.addEventListener('keydown', onKey); return () => document.removeEventListener('keydown', onKey); }, []); const copy = async () => { await navigator.clipboard?.writeText(LINK).catch(() => undefined); setCopied(true); window.setTimeout(() => setCopied(false), 1500); }; return ( <div className="grid w-full max-w-md gap-6"> <InputGroup> <InputGroupInput ref={search} placeholder="Search schemes" aria-label="Search schemes" aria-keyshortcuts="/" /> <InputGroupAddon> <SearchIcon aria-hidden /> </InputGroupAddon> <InputGroupAddon align="inline-end"> <Kbd>/</Kbd> </InputGroupAddon> </InputGroup>
<Field> <FieldLabel htmlFor="group-site">Website</FieldLabel> <InputGroup> <InputGroupAddon> <InputGroupText>https://</InputGroupText> </InputGroupAddon> <InputGroupInput id="group-site" placeholder="example.com" /> <InputGroupAddon align="inline-end"> <InputGroupText>/schemes</InputGroupText> </InputGroupAddon> </InputGroup> </Field>
<Field> <FieldLabel htmlFor="group-link">Share link</FieldLabel> <InputGroup> <InputGroupInput id="group-link" value={LINK} readOnly /> <InputGroupAddon align="inline-end"> <InputGroupButton size="icon-xs" aria-label={copied ? 'Copied' : 'Copy link'} onClick={copy} > {copied ? <CheckIcon aria-hidden /> : <CopyIcon aria-hidden />} </InputGroupButton> </InputGroupAddon> </InputGroup> </Field>
<Field> <FieldLabel htmlFor="group-message">Message</FieldLabel> <InputGroup> <InputGroupTextarea id="group-message" value={message} onChange={(event) => setMessage(event.target.value)} placeholder="Write a message" /> <InputGroupAddon align="block-end" className="border-t"> <InputGroupText>{message.length} characters</InputGroupText> <InputGroupButton variant="default" size="sm" className="ml-auto" disabled={message.trim() === ''} onClick={() => setMessage('')} > Send </InputGroupButton> </InputGroupAddon> </InputGroup> </Field> </div> );}Usage#
import { InputGroup, InputGroupAddon, InputGroupInput,} from '@workspace/active-ui/components/primitives/input-group';
<InputGroup> <InputGroupInput placeholder="Search" aria-label="Search" /> <InputGroupAddon> <SearchIcon aria-hidden /> </InputGroupAddon></InputGroup>;Anatomy#
Input: the border,Group role="group". It takes the focus ring of the control inside it, and the error border when that control hasaria-.invalid InputorGroup Input Input: the control, without a border of its own. Use these, not a plainGroup Textarea Input: the group finds its control by them.Input: what is attached.Group Addon alignplaces it:inline-(the default) andstart inline-: before or after the text, on the same line;end block-andstart block-: above or below it, across the full width, for a header or a toolbar. Addend border-orb border-to separate it.t
The order of the children does not matter;
aligndecides. A click on an addon that is not a button focuses the input.Input: text or an icon in an addon, in the muted colour.Group Text Input: a compact button in an addon,Group Button ghostand sizexsby default, andtype="button", so it never submits the form by accident.
What your application provides#
An accessible name for the control (
FieldorLabel aria-), and for every icon-only button.label The behaviour of the buttons and of any shortcut you show. A
Kbdin an addon only shows a key; the example binds/itself.The value; a prefix or suffix in an addon is not part of it.
Accessibility and keyboard#
The control and each button are their own tab stops.
A prefix or suffix is visible text, not part of the label. When it matters for understanding, such as a unit, repeat it in the label or the description.
API#
InputGroupAddon
Props
- Type
"block-end" "block-start" "inline-end" "inline-start" null- Default
'inline-start'
Where the addon sits: inline- and inline- before or after the text on the same line, block- and block- above or below it across the full width. The order of the children does not matter.
Other props, such as the standard attributes of the underlying element, className and ref, are passed through.
InputGroupButton
Props marked Base UI are behaviour of the Base UI part this component is built on.
Props
Other props, such as the standard attributes of the underlying element, className and ref, are passed through.
Parts that take only their elementโs attributes
Input: the attributes of aGroup <div>, with className and ref.Input: the attributes of aGroup Text <span>, with className and ref.Input: the attributes of aGroup Input <input>, with className and ref.Input: the attributes of aGroup Textarea <textarea>, with className and ref.
This page adapts the Input Group documentation of shadcn/ui (MIT licence) to this package; see Third-party notices.