YaVendio Registry
Components

YA Input Group

A composable input group component for combining inputs with addons like icons, text, and buttons

The YaInputGroup is a flexible composition component in the YaVendio Design System. It allows you to combine inputs or textareas with addons such as icons, text, buttons, and more at various positions.

Quick Start

pnpm dlx shadcn@latest add @yavendio/ya-input-group
npx shadcn@latest add @yavendio/ya-input-group
yarn dlx shadcn@latest add @yavendio/ya-input-group
import {
  YaInputGroup,
  YaInputGroupAddon,
  YaInputGroupInput,
} from '@/components/ui/ya-input-group'
import { Search } from 'lucide-react'

export default function Example() {
  return (
    <YaInputGroup>
      <YaInputGroupInput placeholder="Search..." />
      <YaInputGroupAddon>
        <Search />
      </YaInputGroupAddon>
    </YaInputGroup>
  )
}

Basic Usage

The component uses a composition pattern with several subcomponents:

12 results
<YaInputGroup>
  <YaInputGroupInput placeholder="Search..." />
  <YaInputGroupAddon>
    <Search />
  </YaInputGroupAddon>
  <YaInputGroupAddon align="inline-end">12 results</YaInputGroupAddon>
</YaInputGroup>

Component Structure

ComponentDescription
YaInputGroupContainer wrapper with border and focus states
YaInputGroupAddonAddon container with position alignment
YaInputGroupInputStyled input element
YaInputGroupTextareaStyled textarea element
YaInputGroupButtonButton for use within addons
YaInputGroupTextText element for use within addons

Addon Alignment

The align prop on YaInputGroupAddon positions the addon relative to the input.

AlignDescriptionUsage
inline-startLeft side of input (default)Icons, prefixes
inline-endRight side of inputSuffixes, buttons
block-startAbove textarea (header bar)File names, tabs
block-endBelow textarea (footer bar)Character count, submit

For proper focus management, YaInputGroupAddon should always be placed after YaInputGroupInput or YaInputGroupTextarea in the DOM. Use the align prop to visually position the addon.

Examples

With Icons

<YaInputGroup>
  <YaInputGroupInput placeholder="Search..." />
  <YaInputGroupAddon>
    <Search />
  </YaInputGroupAddon>
</YaInputGroup>

<YaInputGroup>
  <YaInputGroupInput placeholder="Card number" />
  <YaInputGroupAddon>
    <CreditCard />
  </YaInputGroupAddon>
  <YaInputGroupAddon align="inline-end">
    <Check />
  </YaInputGroupAddon>
</YaInputGroup>

With Text

$
USD
https://
.com
@company.com
<YaInputGroup>
  <YaInputGroupInput placeholder="0.00" />
  <YaInputGroupAddon>
    <YaInputGroupText>$</YaInputGroupText>
  </YaInputGroupAddon>
  <YaInputGroupAddon align="inline-end">
    <YaInputGroupText>USD</YaInputGroupText>
  </YaInputGroupAddon>
</YaInputGroup>

<YaInputGroup>
  <YaInputGroupInput placeholder="example.com" />
  <YaInputGroupAddon>
    <YaInputGroupText>https://</YaInputGroupText>
  </YaInputGroupAddon>
</YaInputGroup>

With Button

https://
<YaInputGroup>
  <YaInputGroupInput placeholder="Enter URL..." />
  <YaInputGroupAddon>
    <YaInputGroupText>https://</YaInputGroupText>
  </YaInputGroupAddon>
  <YaInputGroupAddon align="inline-end">
    <YaInputGroupButton variant="default">Search</YaInputGroupButton>
  </YaInputGroupAddon>
</YaInputGroup>

With Spinner

Loading...
<YaInputGroup>
  <YaInputGroupInput placeholder="Saving..." disabled />
  <YaInputGroupAddon align="inline-end">
    <Loader2 className="animate-spin" />
  </YaInputGroupAddon>
</YaInputGroup>

With Textarea

For textareas, use block-start and block-end alignment for header/footer bars.

script.js
Line 1, Column 1
<YaInputGroup className="flex-col items-stretch">
  <YaInputGroupTextarea
    placeholder="console.log('Hello, world!');"
    className="min-h-[160px]"
    hasBlockStart
    hasBlockEnd
  />
  <YaInputGroupAddon align="block-start">
    <YaInputGroupText className="font-mono font-medium text-foreground">
      script.js
    </YaInputGroupText>
    <div className="flex items-center gap-1">
      <YaInputGroupButton size="icon-xs" aria-label="Refresh">
        <RefreshCw className="size-3" />
      </YaInputGroupButton>
      <YaInputGroupButton size="icon-xs" aria-label="Copy">
        <Copy className="size-3" />
      </YaInputGroupButton>
    </div>
  </YaInputGroupAddon>
  <YaInputGroupAddon align="block-end">
    <YaInputGroupText className="text-xs">Line 1, Column 1</YaInputGroupText>
    <YaInputGroupButton variant="default" size="sm">
      Run <Send className="ml-1 size-3" />
    </YaInputGroupButton>
  </YaInputGroupAddon>
</YaInputGroup>

When using block addons with YaInputGroupTextarea, set hasBlockStart and/or hasBlockEnd to true to add proper padding for the absolute-positioned addon bars.

States

Destructive

Please enter a valid email address

<YaInputGroup destructive>
  <YaInputGroupInput placeholder="Invalid email" />
  <YaInputGroupAddon><Mail /></YaInputGroupAddon>
</YaInputGroup>

Disabled

<YaInputGroup>
  <YaInputGroupInput placeholder="Disabled input" disabled />
  <YaInputGroupAddon><Search /></YaInputGroupAddon>
</YaInputGroup>

Prompt Example

A common use case is a prompt input with character counter and submit button.

0/280
const [message, setMessage] = useState('')
const maxLength = 280

<YaInputGroup className="flex-col items-stretch">
  <YaInputGroupTextarea
    placeholder="Ask, Search or Chat"
    value={message}
    onChange={(e) => setMessage(e.target.value.slice(0, maxLength))}
    className="min-h-[100px]"
    hasBlockEnd
  />
  <YaInputGroupAddon align="block-end">
    <YaInputGroupText className="text-xs">
      {message.length}/{maxLength}
    </YaInputGroupText>
    <YaInputGroupButton variant="default" size="sm">
      Post
    </YaInputGroupButton>
  </YaInputGroupAddon>
</YaInputGroup>

Props

YaInputGroup

PropTypeDefaultDescription
destructivebooleanfalseApplies error border styling
classNamestring-Additional classes

YaInputGroupAddon

PropTypeDefaultDescription
align'inline-start' | 'inline-end' | 'block-start' | 'block-end''inline-start'Addon position
classNamestring-Additional classes

YaInputGroupInput

PropTypeDefaultDescription
classNamestring-Additional classes

Extends all standard <input> HTML attributes.

YaInputGroupTextarea

PropTypeDefaultDescription
hasBlockStartbooleanfalseAdds top padding for block-start addon
hasBlockEndbooleanfalseAdds bottom padding for block-end addon
classNamestring-Additional classes

Extends all standard <textarea> HTML attributes.

YaInputGroupButton

PropTypeDefaultDescription
size'xs' | 'icon-xs' | 'sm' | 'icon-sm''xs'Button size
variant'default' | 'ghost''ghost'Button variant
classNamestring-Additional classes

Extends all standard <button> HTML attributes.

YaInputGroupText

PropTypeDefaultDescription
classNamestring-Additional classes

Extends all standard <span> HTML attributes.

Accessibility

Best Practices

DoDon't
Use align prop to position addonsManually position with CSS
Place addons after input in DOMPut addons before input
Use hasBlockStart/hasBlockEnd with textareaForget padding for block addons
Use YaInputGroupText for text contentUse plain text nodes
Use YaInputGroupButton for actionsUse external button components

TypeScript

import { type VariantProps } from 'class-variance-authority'
import {
  yaInputGroupVariants,
  yaInputGroupAddonVariants,
  yaInputGroupButtonVariants,
  yaInputGroupInputVariants,
} from '@/components/ui/ya-input-group'

type InputGroupDestructive = VariantProps<typeof yaInputGroupVariants>['destructive']
type AddonAlign = VariantProps<typeof yaInputGroupAddonVariants>['align']
type ButtonSize = VariantProps<typeof yaInputGroupButtonVariants>['size']

On this page