# Input Group Affixes - Status: `completed` - Owner: `codex` - Date: `2026-03-25` ## Goal Add a reusable input-affix composition layer so search icons, badges, and suffix actions stop being page-level absolute-position wrappers and instead ship as a stable Cadence UI pattern. ## Scope - In scope: - add a public `InputGroup` companion pattern with prefix and suffix slots - keep the existing `Input` API intact while letting it compose cleanly inside the new group - update at least one real docs surface that currently hand-rolls affix layout - add Storybook coverage and unit tests for the new slot and field wiring behavior - Out of scope: - redesigning `Field` or introducing a second label/help-text abstraction - broad visual restyling of all text-entry surfaces - migrating every existing search field in one pass ## Constraints - Preserve the existing `Input` ref and prop contract for non-grouped usage. - Follow the current `Field` state inheritance rules for disabled, invalid, readonly, and required behavior. - Expose stable `data-slot` hooks for the new affix anatomy. - Keep the new pattern token-driven and visually aligned with the current input chrome. ## Affected Surfaces - `docs/exec-plans/2026-03-25-input-group-affixes.md` - `packages/ui/src/lib/contracts.ts` - `packages/ui/src/components/input.tsx` - `packages/ui/src/components/input-group.tsx` - `packages/ui/src/components/input-group.variants.ts` - `packages/ui/src/components/input-group.test.tsx` - `packages/ui/src/components/data-table.tsx` - `packages/ui/src/components/command.tsx` - `packages/ui/src/components/command.test.tsx` - `packages/ui/src/index.ts` - `apps/docs/src/components/input-group.stories.tsx` - `apps/docs/src/revenue-dashboard.stories.tsx` - `registry/index.json` ## Plan 1. Add the execution plan and define the new input-affix pattern against the existing `Input`/`Field` contract. 2. Implement `InputGroup` plus grouped-input behavior without regressing standalone `Input`. 3. Migrate the most obvious repeated search wrapper surfaces to the new composition layer. 4. Add stories, tests, and registry updates, then run the narrowest useful validation passes. ## Validation - `pnpm --filter @ai-ui/ui test -- --run packages/ui/src/components/input-group.test.tsx packages/ui/src/components/input.test.tsx packages/ui/src/components/command.test.tsx` - `pnpm --filter @ai-ui/ui typecheck` - `pnpm harness:validate:docs` - `pnpm registry:build` ## Orchestration Task Sketch - `T1`: implement the input group component and integrate standalone input behavior - `T2 -> T1`: migrate docs usage and command/data-table composition to the new slots - `T3 -> T1`: add tests, stories, and registry updates ## Status Log - `2026-03-25 14:29` Read the system-of-record files and confirmed the current `Input` contract has no affix composition layer. - `2026-03-25 14:35` Chose a sibling `InputGroup` pattern over mutating `Input` into a wrapped root so the existing input API stays stable outside grouped usage. - `2026-03-25 15:17` Implemented `InputGroup`, grouped input behavior, and the first consumer migrations in `CommandInput`, `DataTableSearch`, and the revenue dashboard story. - `2026-03-25 15:24` Verified `pnpm --filter @ai-ui/ui test -- --run packages/ui/src/components/input-group.test.tsx packages/ui/src/components/input.test.tsx packages/ui/src/components/command.test.tsx packages/ui/src/components/data-table.test.tsx`, `pnpm --filter @ai-ui/ui typecheck`, `pnpm harness:validate:docs`, and `pnpm registry:build`.