Experience System
Components

Input Group

Single bordered shell combining an input with leading or trailing addons, text, and buttons.

https://

Installation

The components are exported from @by/experience-system. Add the package with your package manager:

pnpm add @by/experience-system

In this monorepo, depend on the workspace package (for example via workspace:* or your catalog) so imports resolve to packages/experience-system.

Composition

Use the following composition to build an InputGroup:

InputGroup
├── InputGroupAddon (optional, repeat)
│   ├── InputGroupText (optional)
│   └── InputGroupButton (optional)
├── InputGroupInput
└── InputGroupAddon (optional)

InputGroupInput (or a SelectTrigger wired like a group control) should carry data-slot="input-group-control" so the shell applies focus and invalid styles. Addons use align for block/inline placement.

Usage

import {
  InputGroup,
  InputGroupAddon,
  InputGroupInput,
  InputGroupText,
} from '@by/experience-system';

InputGroup and its parts are client components ('use client'). Use them inside a Client Component or a dynamic import when using the Next.js App Router.

<InputGroup>
  <InputGroupAddon>
    <InputGroupText>https://</InputGroupText>
  </InputGroupAddon>
  <InputGroupInput placeholder="example.com" />
</InputGroup>

Examples

Overview

Trailing icon addon and leading URL prefix with a tooltip help InputGroupButton.

https://

With icons

Leading and trailing icon addons.

With buttons

Copy, popover, and outline action buttons in addons.

https://

With tooltips

Help buttons inside trailing addons.

Filled appearance

appearance="filled" on the shell to match Input filled.

https://

Sizes

sm, md, and lg shells with aligned addon typography.

sm
md
lg

API Reference

Subsection titles name the exports from @by/experience-system. InputGroupInput forwards to Input; see the Input page for control props (size, appearance, readOnly, aria-invalid, …). The shell mirrors the shared field-control surface with the group context.

InputGroup

PropTypeDefault
appearancedefault | filleddefault
sizesm | md | lgmd
Data attributeValues
data-slotinput-group
data-appearancemirrors appearance
data-sizemirrors size
data-disabledpresent when an inner control reports disabled

Renders role="group". Also accepts standard div attributes.

InputGroupAddon

PropTypeDefault
aligninline-start | inline-end | block-start | block-endinline-start
groupSizesm | md | lgfrom context
Data attributeValues
data-slotinput-group-addon
data-alignmirrors align

Clicking the addon focuses the nested input unless the event target is a button. Also accepts standard div attributes.

InputGroupButton

Button with group-aware sizing defaults. size overrides the mapped default from group size.

Also accepts Button props (excluding the internal size resolution when omitted).

InputGroupText

Muted inline text sized from group size.

Also accepts standard span attributes.

InputGroupInput

Forwards to Input; size and appearance default from InputGroup when omitted. Merges classes for borderless group layout.

Data attributeValues
data-slotinput-group-control

Also accepts Input props.

Accessibility

Keep a single tab stop in the text field unless addons expose real controls (button, a). Provide aria-label or visible text for icon-only InputGroupButton elements. Surface validation with aria-invalid on InputGroupInput so addon text color follows the invalid state. See MDN — input.

Keyboard interactions

KeyDescription
TabMoves focus through inputs and interactive addons.
Space / EnterActivates InputGroupButton controls when focused.

Source in the repo: packages/experience-system/src/components/InputGroup/InputGroup.tsx. Agent-oriented contracts: packages/experience-system/src/components/InputGroup/InputGroup.instructions.md.