Thrive Design System

Components

Input

A comprehensive collection of input components including text inputs, grouped inputs with addons, shortcode inputs, number inputs, and tag inputs

Installation

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

Usage

Import the input components from the package:

import { 
  Input, 
  InputGroup, 
  InputGroupAddon, 
  InputGroupInput,
  InputGroupButton,
  InputShortcode,
  NumberInput,
  TagsInput
} from '@thrivecart/ui';

Basic Input

Default Input

Simple Input

Basic text input

<Input placeholder="Enter text..." />

Input Variants

All Variants

Different states for validation feedback

<div className="flex flex-col gap-4 w-72">
<Input variant="normal" placeholder="Normal input" />
<Input variant="destructive" placeholder="Error input" />
<Input variant="success" placeholder="Success input" />
<Input variant="warning" placeholder="Warning input" />
</div>

Input Sizes

Size Variants

Three size options

<div className="flex flex-col gap-4 w-72">
<Input size="sm" placeholder="Small input" />
<Input size="md" placeholder="Medium input (default)" />
<Input size="lg" placeholder="Large input" />
</div>

With Adornments

Start and End Adornments

Icons or text before/after the input

USD
<div className="flex flex-col gap-4 w-72">
<Input startAdornment={<MdSearch size={18} />} placeholder="Search..." />
<Input endAdornment={<MdEmail size={18} />} placeholder="Email address" />
<Input
  startAdornment={<MdAttachMoney size={18} />}
  endAdornment={<span className="text-xs text-ink-light">USD</span>}
  placeholder="0.00"
/>
</div>

Password Input

Password Toggle

Password input with visibility toggle

function PasswordInput() {
const [showPassword, setShowPassword] = React.useState(false);

return (
  <Input
    type={showPassword ? 'text' : 'password'}
    startAdornment={<MdLock size={18} />}
    endAdornment={
      <button
        type="button"
        onClick={() => setShowPassword(!showPassword)}
        className="hover:text-ink transition-colors"
      >
        {showPassword ? <MdVisibilityOff size={18} /> : <MdVisibility size={18} />}
      </button>
    }
    placeholder="Enter password"
  />
);
}

InputGroup

InputGroup allows you to build complex inputs with addons, icons, and buttons.

Basic InputGroup

With Icon Addon

Input with icon prefix

<InputGroup>
<InputGroupAddon>
  <MdSearch size={16} />
</InputGroupAddon>
<InputGroupInput placeholder="Search..." />
</InputGroup>

With Text Addon

URL Input

Input with text prefix

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

With Button

Copy Link Input

Input with action button

<InputGroup>
<InputGroupAddon>
  <MdLink size={16} />
</InputGroupAddon>
<InputGroupInput value="https://example.com/share/abc123" readOnly />
<InputGroupAddon align="inline-end">
  <InputGroupButton variant="ghost" size="xs">
    <MdContentCopy size={14} />
    Copy
  </InputGroupButton>
</InputGroupAddon>
</InputGroup>

InputGroup Sizes

Size Variants

Match input size with your forms

<div className="flex flex-col gap-4 w-72">
<InputGroup size="sm">
  <InputGroupAddon><MdSearch size={14} /></InputGroupAddon>
  <InputGroupInput size="sm" placeholder="Small search..." />
</InputGroup>
<InputGroup size="md">
  <InputGroupAddon><MdSearch size={16} /></InputGroupAddon>
  <InputGroupInput size="md" placeholder="Medium search..." />
</InputGroup>
<InputGroup size="lg">
  <InputGroupAddon><MdSearch size={18} /></InputGroupAddon>
  <InputGroupInput size="lg" placeholder="Large search..." />
</InputGroup>
</div>

InputShortcode

InputShortcode provides an input with shortcode picker and optional emoji support, perfect for email subject lines and personalized content.

With Shortcodes

Input with shortcode picker

function ShortcodeExample() {
const [value, setValue] = React.useState('');

const shortcodes = [
  {
    id: 'contact',
    section: 'Contact',
    text: 'Contact Fields',
    menu: [
      { text: 'First Name', value: '[first_name]' },
      { text: 'Last Name', value: '[last_name]' },
      { text: 'Email', value: '[email]' },
    ],
  },
  {
    id: 'company',
    section: 'Company',
    text: 'Company Fields',
    menu: [
      { text: 'Company Name', value: '[company_name]' },
      { text: 'Website', value: '[website]' },
    ],
  },
];

return (
  <InputShortcode
    value={value}
    onChange={setValue}
    shortcodes={shortcodes}
    placeholder="Enter subject with personalization..."
  />
);
}

With Emoji Support

Shortcode input with emoji picker

<InputShortcode
value={value}
onChange={setValue}
shortcodes={shortcodes}
enableEmoji
placeholder="Type a message with emojis..."
/>

NumberInput

NumberInput provides a numeric input with increment/decrement controls.

Basic Number Input

Quantity selector

function QuantityInput() {
const [value, setValue] = React.useState(50);

return (
  <NumberInput
    value={value}
    onValueChange={setValue}
    min={0}
    max={100}
  />
);
}

With Step and Precision

Temperature input with decimal values

<NumberInput
value={value}
onValueChange={setValue}
min={-50}
max={50}
step={0.5}
precision={1}
/>

TagsInput

TagsInput allows users to enter multiple values as tags or chips.

Basic Tags Input

Multi-value input for technologies

function TagsExample() {
const [values, setValues] = React.useState(['React', 'TypeScript']);

return (
  <TagsInput value={values} onValueChange={setValues}>
    <TagsInputLabel>Technologies</TagsInputLabel>
    <TagsInputList>
      {values.map(value => (
        <TagsInputItem key={value} value={value}>
          {value}
        </TagsInputItem>
      ))}
      <TagsInputInput placeholder="Add technology..." />
    </TagsInputList>
  </TagsInput>
);
}

Best Practices

Use appropriate variants

Use destructive variant for errors, success for valid states, and warning for cautions.

Provide clear placeholders

Use descriptive placeholder text that indicates the expected input format.

Use icons meaningfully

Icons in adornments should reinforce the input's purpose (search icon for search, lock for password).

Match sizes consistently

Use the same size for related form elements (inputs, buttons, selects).

Don't use too many adornments

Limit adornments to avoid cluttering the input. Usually one start and one end is sufficient.

Don't hide essential information

Don't use placeholder text for important labels or instructions.

Props

Input

PropTypeDefaultDescription
variant'normal' | 'destructive' | 'success' | 'warning''normal'Visual variant
size'sm' | 'md' | 'lg''md'Input size
startAdornmentReactNode-Content before input
endAdornmentReactNode-Content after input
classNamestring-Additional className

InputGroup

PropTypeDefaultDescription
size'sm' | 'md' | 'lg''md'Size of the group
classNamestring-Additional className

InputGroupAddon

PropTypeDefaultDescription
align'inline-start' | 'inline-end' | 'block-start' | 'block-end''inline-start'Position of addon

InputShortcode

PropTypeDefaultDescription
valuestring-Input value
onChange(value: string) => void-Change handler
shortcodesShortcodeGroup[]-Shortcode definitions
enableEmojibooleanfalseEnable emoji picker
onLoadShortcodes() => Promise<ShortcodeGroup[]>-Async shortcode loader

NumberInput

PropTypeDefaultDescription
valuenumber-Current value
onValueChange(value: number) => void-Change handler
minnumber-Minimum value
maxnumber-Maximum value
stepnumber1Increment step
precisionnumber0Decimal precision
variant'normal' | 'destructive' | 'success''normal'Visual variant

Accessibility

Form Labels

Always pair inputs with Label components for accessibility. Use htmlFor to associate labels with inputs.

  • All inputs support standard ARIA attributes
  • InputGroup maintains focus styling for the group
  • TagsInput supports keyboard navigation and deletion
  • NumberInput supports keyboard increment/decrement with arrow keys
  • Adornment buttons should have aria-label for screen readers