Thrive Design System

Components

Input Group

A compound input component that combines text inputs with addons, buttons, or text elements for contextual input fields.

Installation

npm install @thrivecart/ui
yarn add @thrivecart/ui
pnpm add @thrivecart/ui
bun add @thrivecart/ui

Usage

import {
  InputGroup,
  InputGroupAddon,
  InputGroupButton,
  InputGroupInput,
  InputGroupText,
  InputGroupTextarea,
} from '@thrivecart/ui';

Align

Use the align prop on InputGroupAddon to position the addon relative to the input.

DOM Order

For proper focus management, InputGroupAddon should always be placed after InputGroupInput or InputGroupTextarea in the DOM. Use the align prop to visually position the addon.

inline-start

Position the addon at the start of the input. This is the default.

Inline Start

Addon at the start of the input

<InputGroup>
<InputGroupInput placeholder="Search contacts..." />
<InputGroupAddon align="inline-start">
  <MdSearch />
</InputGroupAddon>
</InputGroup>

inline-end

Position the addon at the end of the input.

Inline End

Addon at the end of the input

<InputGroup>
<InputGroupInput placeholder="Enter your email" />
<InputGroupAddon align="inline-end">
  <MdEmail />
</InputGroupAddon>
</InputGroup>

block-start

Position the addon above the input (useful for labels or helper content inside the group).

Block Start

Addon above the textarea

Message
<InputGroup>
<InputGroupTextarea placeholder="Write your message..." rows={3} />
<InputGroupAddon align="block-start">
  <InputGroupText>Message</InputGroupText>
</InputGroupAddon>
</InputGroup>

block-end

Position the addon below the input (common for textarea action bars).

Block End

Addon below the textarea with action buttons

<InputGroup>
<InputGroupTextarea placeholder="Type a message..." rows={3} />
<InputGroupAddon align="block-end">
  <InputGroupButton size="icon-xs" aria-label="Attach">
    <MdLink />
  </InputGroupButton>
  <InputGroupButton>
    <MdSend /> Send
  </InputGroupButton>
</InputGroupAddon>
</InputGroup>

Examples

Icon

Icon Addons

Inputs with leading or trailing icons

<div className="flex flex-col gap-3">
<InputGroup>
  <InputGroupInput placeholder="Search..." />
  <InputGroupAddon align="inline-start">
    <MdSearch />
  </InputGroupAddon>
</InputGroup>
<InputGroup>
  <InputGroupInput placeholder="Enter password" type="password" />
  <InputGroupAddon align="inline-start">
    <MdLock />
  </InputGroupAddon>
  <InputGroupAddon align="inline-end">
    <InputGroupButton size="icon-xs" variant="ghost" aria-label="Toggle visibility">
      <MdVisibility />
    </InputGroupButton>
  </InputGroupAddon>
</InputGroup>
</div>

Text

Text Addons

Inputs with text prefixes and suffixes

https://
$
USD
@thrivecart.com
<div className="flex flex-col gap-3">
<InputGroup>
  <InputGroupInput placeholder="example.com" />
  <InputGroupAddon align="inline-start">
    <InputGroupText>https://</InputGroupText>
  </InputGroupAddon>
</InputGroup>
<InputGroup>
  <InputGroupInput placeholder="0.00" />
  <InputGroupAddon align="inline-start">
    <InputGroupText>$</InputGroupText>
  </InputGroupAddon>
  <InputGroupAddon align="inline-end">
    <InputGroupText>USD</InputGroupText>
  </InputGroupAddon>
</InputGroup>
<InputGroup>
  <InputGroupInput placeholder="username" />
  <InputGroupAddon align="inline-end">
    <InputGroupText>@thrivecart.com</InputGroupText>
  </InputGroupAddon>
</InputGroup>
</div>

Button

Button Addons

Inputs with action buttons

<div className="flex flex-col gap-3">
<InputGroup>
  <InputGroupInput placeholder="Search products..." />
  <InputGroupAddon align="inline-end">
    <InputGroupButton>Search</InputGroupButton>
  </InputGroupAddon>
</InputGroup>
<InputGroup>
  <InputGroupInput placeholder="https://thrivecart.com/checkout/abc123" readOnly />
  <InputGroupAddon align="inline-end">
    <InputGroupButton size="icon-xs" aria-label="Copy link">
      <MdContentCopy />
    </InputGroupButton>
  </InputGroupAddon>
</InputGroup>
</div>

Textarea

Textarea with Actions

Textarea input with a bottom action bar

<InputGroup>
<InputGroupTextarea placeholder="Write a note..." rows={4} />
<InputGroupAddon align="block-end">
  <InputGroupButton size="icon-xs" aria-label="Attach file">
    <MdLink />
  </InputGroupButton>
  <InputGroupButton>
    <MdSend /> Send
  </InputGroupButton>
</InputGroupAddon>
</InputGroup>

Sizes

Input Group Sizes

Available in small, medium, and large

<div className="flex flex-col gap-3">
<InputGroup size="sm">
  <InputGroupInput placeholder="Small" />
  <InputGroupAddon align="inline-start">
    <MdSearch />
  </InputGroupAddon>
</InputGroup>
<InputGroup size="md">
  <InputGroupInput placeholder="Medium (default)" />
  <InputGroupAddon align="inline-start">
    <MdSearch />
  </InputGroupAddon>
</InputGroup>
<InputGroup size="lg">
  <InputGroupInput placeholder="Large" />
  <InputGroupAddon align="inline-start">
    <MdSearch />
  </InputGroupAddon>
</InputGroup>
</div>

Combined

Combined Addons

Input with both start and end addons

<div className="flex flex-col gap-3">
<InputGroup>
  <InputGroupInput placeholder="0.00" />
  <InputGroupAddon align="inline-start">
    <MdAttachMoney />
  </InputGroupAddon>
  <InputGroupAddon align="inline-end">
    <InputGroupButton>Apply</InputGroupButton>
  </InputGroupAddon>
</InputGroup>
<InputGroup>
  <InputGroupInput placeholder="Enter discount" />
  <InputGroupAddon align="inline-end">
    <MdPercent />
  </InputGroupAddon>
</InputGroup>
</div>

Best Practices

Keep addons concise

Addons should be short labels, icons, or single buttons. Keep text brief.

Place addon after input in DOM

Always place InputGroupAddon after the input element and use the align prop to position it visually. This ensures correct focus navigation.

Match sizes consistently

Use the same size prop across all InputGroup children for visual consistency.

Don't nest complex components

Avoid placing dropdowns or multi-step interactions inside addons.

Don't overload with buttons

Limit to 1-2 buttons per addon to keep the UI clean and clear.

Props

InputGroup

PropTypeDefaultDescription
size'sm' | 'md' | 'lg''md'Controls height and border radius
classNamestring-Additional className

InputGroupAddon

PropTypeDefaultDescription
align'inline-start' | 'inline-end' | 'block-start' | 'block-end''inline-start'Position relative to the input
classNamestring-Additional className

Use inline-start / inline-end for InputGroupInput. Use block-start / block-end for InputGroupTextarea.

InputGroupButton

PropTypeDefaultDescription
size'xs' | 'sm' | 'icon-xs' | 'icon-sm''xs'Button size
variant'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link''ghost'Button variant
classNamestring-Additional className

InputGroupText

Static text displayed inside an addon.

PropTypeDefaultDescription
classNamestring-Additional className

InputGroupInput

Replacement for Input with input group styles pre-applied.

PropTypeDefaultDescription
size'sm' | 'md' | 'lg''md'Input size
classNamestring-Additional className

All other props are passed to the underlying Input component.

InputGroupTextarea

Replacement for Textarea with input group styles pre-applied.

PropTypeDefaultDescription
classNamestring-Additional className

All other props are passed to the underlying Textarea component.

Accessibility

  • The input within the group receives focus, not the addons.
  • Clicking an addon focuses the associated input automatically.
  • Keyboard navigation works as expected for the inner input and buttons.
  • Use aria-label on icon-only InputGroupButton elements.