- Accordion
- Avatar
- Badge
- Breadcrumb
- Button
- Calendar
- ChatContainer
- ChatInput
- ChatMessage
- ChatMultiChoiceQuestion
- ChatMultiOptionQuestion
- ChatThinking
- Checkbox
- Combobox
- Container
- CurrencyInput
- DistributionSlider
- Drawer
- Dropdown
- FilePicker
- Grid
- Heading
- Image
- Input
- InputGroup
- Label
- Logo
- MapPin
- Markdown
- Modal
- NativeSelect
- NumberInput
- OptionSlider
- OtpInput
- PhoneInput
- Popover
- Progress
- PropertyCalendar
- RadioGroup
- RadioGroupCards
- ResponsiveModal
- ScrollArea
- SearchBar
- SearchBarFallback
- SearchInput
- Select
- Separator
- Spinner
- Switch
- Table
- Tabs
- Text
- Textarea
- TimePicker
- Toast
- Toggle
- ToggleCard
- ToggleGroup
- Toolbar
- Tooltip
InputGroup
Display additional information or actions alongside input fields
pnpm add @wandercom/design-system-web
import {
InputGroup,
InputGroupAddon,
InputGroupInput,
InputGroupButton,
InputGroupText,
} from '@wandercom/design-system-web/ui/input-group';
export function Example() {
return (
<InputGroup>
<InputGroupAddon>
<SearchIcon />
</InputGroupAddon>
<InputGroupInput placeholder="Search..." />
</InputGroup>
);
}Input groups support two size variants that match the Input component.
Add icons to provide visual context for input fields.
Display static text prefixes like protocols (hint) or inline prefix labels.
Position addons above or below the input for vertical layouts.
Combine the useCharacterLimit hook with the InputGroupCharacterCount addon to add a count/max counter to any input or textarea. The hook is framework-agnostic — its returned value and onValueChange plug into React Hook Form, TanStack Form, or any controlled form library without modification. Place the counter inside an InputGroupAddon aligned inline-end for inputs or block-end for textareas.
Behavior: any input that would push the value past maxLength — typing, paste, drop, IME composition — is rejected, so the value is guaranteed never to exceed the cap. The HTML maxLength attribute is not used because it silently truncates pasted content; this hook rejects the whole paste instead.
import {
InputGroup,
InputGroupAddon,
InputGroupCharacterCount,
InputGroupInput,
useCharacterLimit,
} from '@wandercom/design-system-web/ui/input-group';
export function Example() {
const { count, maxLength, inputProps } = useCharacterLimit({
maxLength: 40,
});
return (
<InputGroup>
<InputGroupInput {...inputProps} placeholder="Listing title" />
<InputGroupAddon align="inline-end">
<InputGroupCharacterCount count={count} maxLength={maxLength} />
</InputGroupAddon>
</InputGroup>
);
}For a textarea, swap InputGroupInput for InputGroupTextarea and align the addon block-end so the counter sits at the bottom of the field.
import {
InputGroup,
InputGroupAddon,
InputGroupCharacterCount,
InputGroupTextarea,
useCharacterLimit,
} from '@wandercom/design-system-web/ui/input-group';
export function Example() {
const { count, maxLength, inputProps } = useCharacterLimit({
maxLength: 70,
});
return (
<InputGroup>
<InputGroupTextarea
{...inputProps}
placeholder="Tell guests what makes this stay special"
rows={4}
/>
<InputGroupAddon align="block-end" className="justify-end">
<InputGroupCharacterCount count={count} maxLength={maxLength} />
</InputGroupAddon>
</InputGroup>
);
}size?:
className?:
align?:
className?:
size?:
variant?:
type?:
className?:
className?:
Inherits font size, line height, and padding from the parent InputGroup size variant automatically.
className?:
type?:
Renders inline as a <span> — place inside an InputGroupAddon to position it. Switches to text-error when count > maxLength and announces the overflow via aria-live="polite" only while over the limit (kept silent during normal typing to avoid noisy per-keystroke readouts).
count:
maxLength:
className?:
Framework-agnostic hook that returns spreadable input props. Works with both <input> and <textarea>. Does not use the HTML maxLength attribute (which silently truncates paste) — instead, it rejects any input event (insertText, insertFromPaste, insertFromDrop, insertCompositionText, etc.) that would push the value past maxLength.
maxLength:
value?:
defaultValue?:
onValueChange?:
Returns an object with value, count, maxLength, and an inputProps object ready to spread onto InputGroupInput or InputGroupTextarea. The spread includes value, onChange, and a ref callback that attaches a native beforeinput listener — the listener enforces maxLength by rejecting any insertion (typing, paste, drop, IME composition) that would exceed the cap, so consumers don't need to handle truncation themselves. The native listener is required because React's synthetic onBeforeInput doesn't reliably cancel the underlying input event.
The InputGroup component includes proper accessibility features:
- Uses
role="group"to indicate grouped elements - Focus states are properly managed across the group
- Invalid states are visually indicated with
aria-invalid - Clicking on addons focuses the input for better usability
For proper focus navigation, the InputGroupAddon component should be placed after the input element when using inline-end alignment.