Components

Input Group

Adds addons, buttons, and helper content to inputs.

Installation

Cortexcn
pnpm dlx shadcn@latest add @cortexcn/input-group

Usage

import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupText, InputGroupInput, InputGroupTextarea } from "@/components/input-group";

Examples

Basic

import { Field, FieldGroup, FieldLabel } from "@/components/field"import { Input } from "@/components/input"import { InputGroup, InputGroupInput } from "@/components/input-group"export function InputGroupBasic() {  return (    <div className="flex flex-col gap-6">      <FieldGroup>        <Field>          <FieldLabel htmlFor="input-default-01">            Default (No Input Group)          </FieldLabel>          <Input placeholder="Placeholder" id="input-default-01" />        </Field>        <Field>          <FieldLabel htmlFor="input-group-02">Input Group</FieldLabel>          <InputGroup>            <InputGroupInput id="input-group-02" placeholder="Placeholder" />          </InputGroup>        </Field>        <Field data-disabled="true">          <FieldLabel htmlFor="input-disabled-03">Disabled</FieldLabel>          <InputGroup>            <InputGroupInput              id="input-disabled-03"              placeholder="This field is disabled"              disabled            />          </InputGroup>        </Field>        <Field data-invalid="true">          <FieldLabel htmlFor="input-invalid-04">Invalid</FieldLabel>          <InputGroup>            <InputGroupInput              id="input-invalid-04"              placeholder="This field is invalid"              aria-invalid="true"            />          </InputGroup>        </Field>      </FieldGroup>    </div>  )}

With addons

First Name
20/240 characters

This is a description of the input group.

(optional)
import { toast } from "sonner"import { Field, FieldDescription, FieldGroup, FieldLabel } from "@/components/field"import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText } from "@/components/input-group"import { CopyIcon, EyeOffIcon, InfoIcon, MicIcon, RadioIcon, SearchIcon, StarIcon } from "lucide-react"export function InputGroupWithAddons() {  return (    <div className="flex flex-col gap-6">      <FieldGroup>        <Field>          <FieldLabel htmlFor="input-icon-left-05">            Addon (inline-start)          </FieldLabel>          <InputGroup>            <InputGroupInput id="input-icon-left-05" />            <InputGroupAddon>              <SearchIcon className="text-muted-foreground" />            </InputGroupAddon>          </InputGroup>        </Field>        <Field>          <FieldLabel htmlFor="input-icon-right-07">            Addon (inline-end)          </FieldLabel>          <InputGroup>            <InputGroupInput id="input-icon-right-07" />            <InputGroupAddon align="inline-end">              <EyeOffIcon />            </InputGroupAddon>          </InputGroup>        </Field>        <Field>          <FieldLabel htmlFor="input-icon-both-09">            Addon (inline-start and inline-end)          </FieldLabel>          <InputGroup>            <InputGroupInput id="input-icon-both-09" />            <InputGroupAddon>              <MicIcon className="text-muted-foreground" />            </InputGroupAddon>            <InputGroupAddon align="inline-end">              <RadioIcon className="animate-pulse text-red-500" />            </InputGroupAddon>          </InputGroup>        </Field>        <Field>          <FieldLabel htmlFor="input-addon-20">Addon (block-start)</FieldLabel>          <InputGroup className="h-auto">            <InputGroupInput id="input-addon-20" />            <InputGroupAddon align="block-start">              <InputGroupText>First Name</InputGroupText>              <InfoIcon className="ml-auto text-muted-foreground" />            </InputGroupAddon>          </InputGroup>        </Field>        <Field>          <FieldLabel htmlFor="input-addon-21">Addon (block-end)</FieldLabel>          <InputGroup className="h-auto">            <InputGroupInput id="input-addon-21" />            <InputGroupAddon align="block-end">              <InputGroupText>20/240 characters</InputGroupText>              <InfoIcon className="ml-auto text-muted-foreground" />            </InputGroupAddon>          </InputGroup>        </Field>        <Field>          <FieldLabel htmlFor="input-icon-both-10">Multiple Icons</FieldLabel>          <InputGroup>            <InputGroupInput id="input-icon-both-10" />            <InputGroupAddon align="inline-end">              <StarIcon />              <InputGroupButton                size="icon-xs"                onClick={() => toast("Copied to clipboard")}              >                <CopyIcon />              </InputGroupButton>            </InputGroupAddon>            <InputGroupAddon>              <RadioIcon className="animate-pulse text-red-500" />            </InputGroupAddon>          </InputGroup>        </Field>        <Field>          <FieldLabel htmlFor="input-description-10">Description</FieldLabel>          <InputGroup>            <InputGroupInput id="input-description-10" />            <InputGroupAddon align="inline-end">              <InfoIcon />            </InputGroupAddon>          </InputGroup>          <FieldDescription>            This is a description of the input group.          </FieldDescription>        </Field>        <Field>          <FieldLabel htmlFor="input-label-10">Label</FieldLabel>          <InputGroup>            <InputGroupAddon>              <FieldLabel htmlFor="input-label-10">Label</FieldLabel>            </InputGroupAddon>            <InputGroupInput id="input-label-10" />          </InputGroup>          <InputGroup>            <InputGroupInput id="input-optional-12" aria-label="Optional" />            <InputGroupAddon align="inline-end">              <InputGroupText>(optional)</InputGroupText>            </InputGroupAddon>          </InputGroup>        </Field>      </FieldGroup>    </div>  )}

With buttons

import { Button } from "@/components/button"import { Field, FieldGroup, FieldLabel } from "@/components/field"import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from "@/components/input-group"import { CopyIcon, TrashIcon } from "lucide-react"export function InputGroupWithButtons() {  return (    <div className="flex flex-col gap-6">      <FieldGroup>        <Field>          <FieldLabel htmlFor="input-button-13">Button</FieldLabel>          <InputGroup>            <InputGroupInput id="input-button-13" />            <InputGroupAddon>              <InputGroupButton>Default</InputGroupButton>            </InputGroupAddon>          </InputGroup>          <InputGroup>            <InputGroupInput id="input-button-14" />            <InputGroupAddon>              <InputGroupButton variant="outline">Outline</InputGroupButton>            </InputGroupAddon>          </InputGroup>          <InputGroup>            <InputGroupInput id="input-button-15" />            <InputGroupAddon>              <InputGroupButton variant="secondary">Secondary</InputGroupButton>            </InputGroupAddon>          </InputGroup>          <InputGroup>            <InputGroupInput id="input-button-16" />            <InputGroupAddon align="inline-end">              <InputGroupButton variant="secondary">Button</InputGroupButton>            </InputGroupAddon>          </InputGroup>          <InputGroup>            <InputGroupInput id="input-button-17" />            <InputGroupAddon align="inline-end">              <InputGroupButton size="icon-xs">                <CopyIcon />              </InputGroupButton>            </InputGroupAddon>          </InputGroup>          <InputGroup>            <InputGroupInput id="input-button-18" />            <InputGroupAddon align="inline-end">              <InputGroupButton variant="secondary" size="icon-xs">                <TrashIcon />              </InputGroupButton>            </InputGroupAddon>          </InputGroup>        </Field>      </FieldGroup>    </div>  )}

With kbd

⌘K
⌘K
Ask AI
Tab
CtrlC

This username is available.

12 results
Disabled

This is a description of the input group.

import { Field, FieldDescription, FieldGroup, FieldLabel } from "@/components/field"import { Input } from "@/components/input"import { InputGroup, InputGroupAddon, InputGroupInput } from "@/components/input-group"import { Kbd, KbdGroup } from "@/components/kbd"import { Spinner } from "@/components/spinner"import { CheckIcon, InfoIcon, SearchIcon, SparklesIcon } from "lucide-react"export function InputGroupWithKbd() {  return (    <div className="flex flex-col gap-6">      <FieldGroup>        <Field>          <FieldLabel htmlFor="input-kbd-22">Input Group with Kbd</FieldLabel>          <InputGroup>            <InputGroupInput id="input-kbd-22" />            <InputGroupAddon>              <Kbd>⌘K</Kbd>            </InputGroupAddon>          </InputGroup>          <InputGroup>            <InputGroupInput id="input-kbd-23" />            <InputGroupAddon align="inline-end">              <Kbd>⌘K</Kbd>            </InputGroupAddon>          </InputGroup>          <InputGroup>            <InputGroupInput              id="input-search-apps-24"              placeholder="Search for Apps..."            />            <InputGroupAddon align="inline-end">Ask AI</InputGroupAddon>            <InputGroupAddon align="inline-end">              <Kbd>Tab</Kbd>            </InputGroupAddon>          </InputGroup>          <InputGroup>            <InputGroupInput              id="input-search-type-25"              placeholder="Type to search..."            />            <InputGroupAddon align="inline-start">              <SparklesIcon />            </InputGroupAddon>            <InputGroupAddon align="inline-end">              <KbdGroup>                <Kbd>Ctrl</Kbd>                <Kbd>C</Kbd>              </KbdGroup>            </InputGroupAddon>          </InputGroup>        </Field>        <Field>          <FieldLabel htmlFor="input-username-26">Username</FieldLabel>          <InputGroup>            <InputGroupInput id="input-username-26" defaultValue="shadcn" />            <InputGroupAddon align="inline-end">              <div className="flex size-4 items-center justify-center rounded-full bg-green-500 dark:bg-green-800">                <CheckIcon className="size-3 text-white" />              </div>            </InputGroupAddon>          </InputGroup>          <FieldDescription className="text-green-700">            This username is available.          </FieldDescription>        </Field>        <InputGroup>          <InputGroupInput            id="input-search-docs-27"            placeholder="Search documentation..."          />          <InputGroupAddon>            <SearchIcon />          </InputGroupAddon>          <InputGroupAddon align="inline-end">12 results</InputGroupAddon>        </InputGroup>        <InputGroup data-disabled="true">          <InputGroupInput            id="input-search-disabled-28"            placeholder="Search documentation..."            disabled          />          <InputGroupAddon>            <SearchIcon />          </InputGroupAddon>          <InputGroupAddon align="inline-end">Disabled</InputGroupAddon>        </InputGroup>        <FieldGroup className="grid grid-cols-2 gap-4">          <Field>            <FieldLabel htmlFor="input-group-11">First Name</FieldLabel>            <InputGroup>              <InputGroupInput id="input-group-11" placeholder="First Name" />              <InputGroupAddon align="inline-end">                <InfoIcon />              </InputGroupAddon>            </InputGroup>          </Field>          <Field>            <FieldLabel htmlFor="input-group-12">Last Name</FieldLabel>            <InputGroup>              <InputGroupInput id="input-group-12" placeholder="Last Name" />              <InputGroupAddon align="inline-end">                <InfoIcon />              </InputGroupAddon>            </InputGroup>          </Field>        </FieldGroup>        <Field data-disabled="true">          <FieldLabel htmlFor="input-group-29">            Loading (&quot;data-disabled=&quot;true&quot;)          </FieldLabel>          <InputGroup>            <InputGroupInput              id="input-group-29"              disabled              defaultValue="shadcn"            />            <InputGroupAddon align="inline-end">              <Spinner />            </InputGroupAddon>          </InputGroup>          <FieldDescription>            This is a description of the input group.          </FieldDescription>        </Field>      </FieldGroup>    </div>  )}

In card

Card with Input Group
This is a card with an input group.
https://
0/500 characters
import { Button } from "@/components/button"import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/card"import { Field, FieldGroup, FieldLabel } from "@/components/field"import { Input } from "@/components/input"import { InputGroup, InputGroupAddon, InputGroupInput, InputGroupText, InputGroupTextarea } from "@/components/input-group"import { ExternalLinkIcon, MailIcon } from "lucide-react"export function InputGroupInCard() {  return (    <div className="flex flex-col gap-6">      <Card className="w-full">        <CardHeader>          <CardTitle>Card with Input Group</CardTitle>          <CardDescription>This is a card with an input group.</CardDescription>        </CardHeader>        <CardContent>          <FieldGroup>            <Field>              <FieldLabel htmlFor="email-input">Email Address</FieldLabel>              <InputGroup>                <InputGroupInput                  id="email-input"                  type="email"                  placeholder="you@example.com"                />                <InputGroupAddon align="inline-end">                  <MailIcon />                </InputGroupAddon>              </InputGroup>            </Field>            <Field>              <FieldLabel htmlFor="website-input">Website URL</FieldLabel>              <InputGroup>                <InputGroupAddon>                  <InputGroupText>https://</InputGroupText>                </InputGroupAddon>                <InputGroupInput id="website-input" placeholder="example.com" />                <InputGroupAddon align="inline-end">                  <ExternalLinkIcon />                </InputGroupAddon>              </InputGroup>            </Field>            <Field>              <FieldLabel htmlFor="feedback-textarea">                Feedback & Comments              </FieldLabel>              <InputGroup>                <InputGroupTextarea                  id="feedback-textarea"                  placeholder="Share your thoughts..."                  className="min-h-[100px]"                />                <InputGroupAddon align="block-end">                  <InputGroupText>0/500 characters</InputGroupText>                </InputGroupAddon>              </InputGroup>            </Field>          </FieldGroup>        </CardContent>        <CardFooter className="justify-end gap-2">          <Button variant="outline">Cancel</Button>          <Button>Submit</Button>        </CardFooter>      </Card>    </div>  )}

Textarea

This is a description of the input group.

This is a description of the input group.

This is a description of the input group.

Ask, Search or Chat...

This is a description of the input group.

0/280 characters
script.js
Line 1, Column 1JavaScript
import { Field, FieldDescription, FieldGroup, FieldLabel } from "@/components/field"import { Input } from "@/components/input"import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupText, InputGroupTextarea } from "@/components/input-group"import { Textarea } from "@/components/textarea"import { ArrowUpIcon, CodeIcon, CopyIcon, InfoIcon, RefreshCwIcon } from "lucide-react"export function InputGroupTextareaExamples() {  return (    <div className="flex flex-col gap-6">      <FieldGroup>        <Field>          <FieldLabel htmlFor="textarea-header-footer-12">            Default Textarea (No Input Group)          </FieldLabel>          <Textarea            id="textarea-header-footer-12"            placeholder="Enter your text here..."          />        </Field>        <Field>          <FieldLabel htmlFor="textarea-header-footer-13">            Input Group          </FieldLabel>          <InputGroup>            <InputGroupTextarea              id="textarea-header-footer-13"              placeholder="Enter your text here..."            />          </InputGroup>          <FieldDescription>            This is a description of the input group.          </FieldDescription>        </Field>        <Field data-invalid="true">          <FieldLabel htmlFor="textarea-header-footer-14">Invalid</FieldLabel>          <InputGroup>            <InputGroupTextarea              id="textarea-header-footer-14"              placeholder="Enter your text here..."              aria-invalid="true"            />          </InputGroup>          <FieldDescription>            This is a description of the input group.          </FieldDescription>        </Field>        <Field data-disabled="true">          <FieldLabel htmlFor="textarea-header-footer-15">Disabled</FieldLabel>          <InputGroup>            <InputGroupTextarea              id="textarea-header-footer-15"              placeholder="Enter your text here..."              disabled            />          </InputGroup>          <FieldDescription>            This is a description of the input group.          </FieldDescription>        </Field>        <Field>          <FieldLabel htmlFor="prompt-31">Addon (block-start)</FieldLabel>          <InputGroup>            <InputGroupTextarea id="prompt-31" />            <InputGroupAddon align="block-start">              <InputGroupText>Ask, Search or Chat...</InputGroupText>              <InfoIcon className="ml-auto text-muted-foreground" />            </InputGroupAddon>          </InputGroup>          <FieldDescription>            This is a description of the input group.          </FieldDescription>        </Field>        <Field>          <FieldLabel htmlFor="textarea-header-footer-30">            Addon (block-end)          </FieldLabel>          <InputGroup>            <InputGroupTextarea              id="textarea-header-footer-30"              placeholder="Enter your text here..."            />            <InputGroupAddon align="block-end">              <InputGroupText>0/280 characters</InputGroupText>              <InputGroupButton                variant="default"                size="icon-xs"                className="ml-auto rounded-full"              >                <ArrowUpIcon />                <span className="sr-only">Send</span>              </InputGroupButton>            </InputGroupAddon>          </InputGroup>        </Field>        <Field>          <FieldLabel htmlFor="textarea-comment-31">Addon (Buttons)</FieldLabel>          <InputGroup>            <InputGroupTextarea              id="textarea-comment-31"              placeholder="Share your thoughts..."              className="min-h-[120px]"            />            <InputGroupAddon align="block-end">              <InputGroupButton variant="ghost" className="ml-auto" size="sm">                Cancel              </InputGroupButton>              <InputGroupButton variant="default" size="sm">                Post Comment              </InputGroupButton>            </InputGroupAddon>          </InputGroup>        </Field>        <Field>          <FieldLabel htmlFor="textarea-code-32">Code Editor</FieldLabel>          <InputGroup>            <InputGroupTextarea              id="textarea-code-32"              placeholder="console.log('Hello, world!');"              className="min-h-[300px] py-3"            />            <InputGroupAddon align="block-start" className="border-b">              <InputGroupText className="font-mono font-medium">                <CodeIcon />                script.js              </InputGroupText>              <InputGroupButton size="icon-xs" className="ml-auto">                <RefreshCwIcon />              </InputGroupButton>              <InputGroupButton size="icon-xs" variant="ghost">                <CopyIcon />              </InputGroupButton>            </InputGroupAddon>            <InputGroupAddon align="block-end" className="border-t">              <InputGroupText>Line 1, Column 1</InputGroupText>              <InputGroupText className="ml-auto">JavaScript</InputGroupText>            </InputGroupAddon>          </InputGroup>        </Field>      </FieldGroup>    </div>  )}

Adapted from the shadcn/ui Input Group (MIT).