Input Group
An input group wraps a form input together with optional prefix and suffix addons (icons, units, currency symbols, action buttons) inside a single ARIA group so that they are perceived and announced as one composite control.
Use it for currency fields with leading symbols, search fields with trailing icon buttons, percentage fields with trailing units, and any input where contextual addons clarify the value.
Example
Show demo markup
<div class="input-group" aria-label="a group wrapping an input with prefix and suffix addons">InputGroup</div>
Usage example
<script lang="ts">
import InputGroup from './InputGroup.svelte';
</script>
<InputGroup label="Amount in US dollars">
{#snippet prefix()}<span aria-hidden="true">$</span>{/snippet}
<input type="number" min="0" step="0.01" />
{#snippet suffix()}<span aria-hidden="true">USD</span>{/snippet}
</InputGroup>
Show Svelte source
// In your Svelte component:
import InputGroup from "lily-design-system-svelte-headless/components/InputGroup/InputGroup.svelte";
<InputGroup>
<!-- list children -->
</InputGroup>
Usage
Currency input with leading symbol:
<InputGroup label="Amount">
<span slot="prefix">$</span>
<TextInput label="Amount" value={amount} onChange={setAmount} />
</InputGroup>
Search input with trailing icon button:
<InputGroup label="Search">
<SearchInput label="Search" value={query} onChange={setQuery} />
<IconButton slot="suffix" label="Submit search" onclick={submit}>
🔍
</IconButton>
</InputGroup>
Percentage input with trailing unit:
<InputGroup label="Discount">
<NumberInput label="Discount" value={discount} onChange={setDiscount} />
<span slot="suffix">%</span>
</InputGroup>
Props
label: string (optional) -- aria-label for the group
prefix: slot (optional) -- content rendered before the input
suffix: slot (optional) -- content rendered after the input
children: slot -- the input the consumer places inside
...restProps: any additional HTML attributes
Keyboard Interactions
- The wrapped input retains its native keyboard behavior.
- Focusable controls inside
prefix / suffix slots (e.g., IconButton) follow their own keyboard behavior.
ARIA
role="group" on the wrapping <div> so assistive technology treats the addons and input as one unit
aria-label rendered when label is provided
- The inner input still requires its own accessible name (label, aria-label, or aria-labelledby)
When to Use
- Use to attach a prefix or suffix addon to a form input.
- Use for currency, percentage, and unit inputs.
- Use for search inputs with trailing action buttons.
When Not to Use
- Do not use as a generic form layout (use Field for label/input/error composition).
- Do not omit a label on the inner input — the group's aria-label does not replace the input's accessible name.
Headless
Provides only the structural wrapper, the prefix and suffix slot containers, and the ARIA group semantics. Visual treatment such as connected borders, addon backgrounds, and focus styling is entirely consumer-supplied.
Styles
Consumer CSS targets .input-group, .input-group-prefix, and .input-group-suffix to apply visual treatment such as shared borders, addon backgrounds, and connected radii.
Testing
- Verify the component renders a
<div> element with class input-group and role="group"
- Verify
aria-label is rendered when the label prop is provided
- Verify the prefix renders inside
<span class="input-group-prefix"> when provided
- Verify the suffix renders inside
<span class="input-group-suffix"> when provided
- Verify children render between prefix and suffix
- Verify focus order is prefix → input → suffix
Advice
- Designers: Use prefix and suffix addons sparingly — overusing them clutters forms. Reserve them for unit symbols, currency markers, and trailing action buttons.
- Developers: Continue to apply a label on the inner input itself (via
<label>, aria-label, or aria-labelledby); the group's label prop names the composite control, not the input.
Implementation Notes
- Renders a
<div> with role="group" and class="input-group"
- Optional prefix renders inside
<span class="input-group-prefix">
- Optional suffix renders inside
<span class="input-group-suffix">
- Children (the actual input) sit between the prefix and suffix
aria-label is rendered when the label prop is provided
- Does not modify the inner input — the consumer is responsible for label association on the input itself
Related components
input — a generic HTML input element
field — a form field wrapper with label, input, and error message
form — a form element for collecting and submitting user data
References
- WAI-ARIA group role: https://www.w3.org/TR/wai-aria-1.2/#group
- WCAG 1.3.1 Info and Relationships: https://www.w3.org/WAI/WCAG22/Understanding/info-and-relationships
Canonical contract
Generated from this component's canonical metadata — the machine-checked source the implementations are held to.
Metadata
- Component: input-group
- PascalCase: InputGroup
- Description: a group wrapping an input with prefix and suffix addons
- Status: beta — implemented and unit-tested in all seven frameworks with an axe-clean demo page; not yet exercised in composed flows
- HTML tag: <div>
- CSS class: .input-group
- Interactive: no (focusable controls inside slots manage their own behavior)
ARIA
role="group" on wrapper aria-label when label prop provided - Inner input continues to require its own name
Keyboard
- Inner input retains native keyboard behavior
- Focusable controls in slots follow their own keyboard behavior
Props
label: string (optional) -- aria-label for the group prefix: slot (optional) -- content before input suffix: slot (optional) -- content after input children: slot -- the input ...restProps: any additional HTML attributes