Combine an input or textarea with addons such as icons, buttons, or labels.
class-variance-authority
lucide-react1'use client'
2
3import React from 'react'
4
5import {
6 InputGroup,
7 InputGroupAddon,
8 InputGroupButton,
9 InputGroupInput,
10 InputGroupText,
11 InputGroupTextarea,
12} from '@/components/ui/input-group'
13
14export function ExampleInputGroups() {
15 return (
16 <div className="w-60 space-y-4 sm:w-80">
17 <InputGroup>
18 <InputGroupAddon align="inline-start">$</InputGroupAddon>
19 <InputGroupInput placeholder="Enter amount" />
20 </InputGroup>
21 <InputGroup>
22 <InputGroupInput placeholder="Enter your username" />
23 <InputGroupAddon align="inline-end">
24 @example.com
25 </InputGroupAddon>
26 </InputGroup>
27 <InputGroup>
28 <InputGroupInput placeholder="Search..." />
29 <InputGroupAddon align="inline-end">
30 <InputGroupButton>Search</InputGroupButton>
31 </InputGroupAddon>
32 </InputGroup>
33 <InputGroup>
34 <InputGroupText className="pl-3">Phone</InputGroupText>
35 <InputGroupInput placeholder="Enter your phone number" />
36 </InputGroup>
37 <InputGroup>
38 <InputGroupAddon align="block-start">Message</InputGroupAddon>
39 <InputGroupTextarea placeholder="Type your message..." className='pt-2'/>
40 </InputGroup>
41 </div>
42 )
43}
44Install the following dependencies:
Used to combine an input field with a dropdown selector for quick option selection.
1'use client'
2
3import React, { useState } from 'react'
4import { ChevronDownIcon } from 'lucide-react'
5
6import { Button } from '@/components/ui/button'
7import {
8 DropdownMenu,
9 DropdownMenuContent,
10 DropdownMenuItem,
11 DropdownMenuTrigger,
12} from '@/components/ui/dropdown-menu'
13import {
14 InputGroup,
15 InputGroupAddon,
16 InputGroupInput,
17} from '@/components/ui/input-group'
18
19export function ExampleInputGroups() {
20 const domains = ['@gmail.com', '@yahoo.com', '@outlook.com']
21 const [selectedDomain, setSelectedDomain] = useState(domains[0])
22
23 return (
24 <div className="w-60 space-y-4 sm:w-80">
25 <InputGroup>
26 <InputGroupInput placeholder="Your email username" />
27 <InputGroupAddon align="inline-end" className="pr-0">
28 <DropdownMenu>
29 <DropdownMenuTrigger asChild>
30 <button type='button' className="flex gap-1 outline-none shrink-0 pr-4 text-xs text-gray items-center justify-between">
31 {selectedDomain || 'Select domain'}
32 <ChevronDownIcon className="size-4 opacity-50" />
33 </button>
34 </DropdownMenuTrigger>
35 <DropdownMenuContent align="start">
36 {domains.map((domain) => (
37 <DropdownMenuItem
38 key={domain}
39 onClick={() => setSelectedDomain(domain)}
40 >
41 {domain}
42 </DropdownMenuItem>
43 ))}
44 </DropdownMenuContent>
45 </DropdownMenu>
46 </InputGroupAddon>
47 </InputGroup>
48 </div>
49 )
50}
51Adds contextual information or guidance beside the input using a tooltip trigger.
1'use client'
2
3import React from 'react'
4import { HelpCircle, HelpCircleIcon, InfoIcon } from 'lucide-react'
5
6import {
7 InputGroup,
8 InputGroupAddon,
9 InputGroupButton,
10 InputGroupInput,
11} from '@/components/ui/input-group'
12import {
13 Tooltip,
14 TooltipContent,
15 TooltipTrigger,
16} from '@/components/ui/tooltip'
17
18export function InputGroupWithTooltips() {
19 return (
20 <div className="grid w-60 gap-4 sm:w-80">
21 <InputGroup>
22 <InputGroupInput placeholder="Enter password" type="password" />
23 <InputGroupAddon align="inline-end">
24 <Tooltip defaultOpen>
25 <TooltipTrigger asChild>
26 <InputGroupButton
27 variant="ghost"
28 size="icon-xs"
29 aria-label="Info"
30 >
31 <InfoIcon />
32 </InputGroupButton>
33 </TooltipTrigger>
34 <TooltipContent>
35 <p>Password must be at least 8 characters</p>
36 </TooltipContent>
37 </Tooltip>
38 </InputGroupAddon>
39 </InputGroup>
40
41 <InputGroup>
42 <InputGroupInput
43 placeholder="Your email address"
44 type="email"
45 />
46 <InputGroupAddon align="inline-end">
47 <Tooltip defaultOpen>
48 <TooltipTrigger asChild>
49 <InputGroupButton
50 variant="ghost"
51 size="icon-xs"
52 aria-label="Help"
53 >
54 <HelpCircle />
55 </InputGroupButton>
56 </TooltipTrigger>
57 <TooltipContent>
58 <p>We'll use this to send you notifications</p>
59 </TooltipContent>
60 </Tooltip>
61 </InputGroupAddon>
62 </InputGroup>
63
64 <InputGroup>
65 <InputGroupInput placeholder="Enter API key" />
66 <InputGroupAddon align="inline-end">
67 <Tooltip>
68 <TooltipTrigger asChild>
69 <InputGroupButton
70 variant="ghost"
71 size="icon-xs"
72 aria-label="Help"
73 >
74 <HelpCircleIcon />
75 </InputGroupButton>
76 </TooltipTrigger>
77 <TooltipContent side="left">
78 <p>Click for help with API keys</p>
79 </TooltipContent>
80 </Tooltip>
81 </InputGroupAddon>
82 </InputGroup>
83 </div>
84 )
85}
86Pairs an input with an action button such as search, submit, or clear.
1'use client'
2
3import * as React from 'react'
4import { Check, Copy, InfoIcon, StarIcon } from 'lucide-react'
5
6import {
7 InputGroup,
8 InputGroupAddon,
9 InputGroupButton,
10 InputGroupInput,
11} from '@/components/ui/input-group'
12import {
13 Popover,
14 PopoverContent,
15 PopoverTrigger,
16} from '@/components/ui/popover'
17
18export function InputGroupButtonDemo() {
19 const [isFavorite, setIsFavorite] = React.useState(false)
20 const [copied, setCopied] = React.useState(false)
21 const value = 'https://example.com/dashboard'
22
23 const handleCopy = async () => {
24 await navigator.clipboard.writeText(value)
25 setCopied(true)
26 setTimeout(() => setCopied(false), 1500)
27 }
28
29 return (
30 <div className="grid w-60 gap-4 sm:w-80">
31 <InputGroup>
32 <InputGroupAddon align="inline-start">
33 <Popover>
34 <PopoverTrigger asChild>
35 <InputGroupButton
36 variant="secondary"
37 size="icon-xs"
38 >
39 <InfoIcon />
40 </InputGroupButton>
41 </PopoverTrigger>
42 <PopoverContent className="rounded-xl p-2 text-sm">
43 <p className="font-medium">Warning</p>
44 <p>
45 Your connection is not secure. Avoid entering
46 sensitive info.
47 </p>
48 </PopoverContent>
49 </Popover>
50 </InputGroupAddon>
51
52 <InputGroupInput placeholder="Enter website URL" />
53 <InputGroupAddon align="inline-end">
54 <InputGroupButton
55 aria-label="Favorite"
56 size="icon-xs"
57 onClick={() => setIsFavorite(!isFavorite)}
58 >
59 <StarIcon
60 data-favorite={isFavorite}
61 className="data-[favorite=true]:fill-primary data-[favorite=true]:stroke-primary"
62 />
63 </InputGroupButton>
64 </InputGroupAddon>
65 </InputGroup>
66
67 <InputGroup>
68 <InputGroupInput placeholder="Search..." />
69 <InputGroupAddon align="inline-end">
70 <InputGroupButton variant="secondary">
71 Search
72 </InputGroupButton>
73 </InputGroupAddon>
74 </InputGroup>
75
76 <InputGroup>
77 <InputGroupInput readOnly value={value} />
78 <InputGroupAddon align="inline-end">
79 <InputGroupButton
80 size="icon-sm"
81 variant="secondary"
82 onClick={handleCopy}
83 aria-label="Copy link"
84 >
85 {copied ? (
86 <Check className="text-green-500" />
87 ) : (
88 <Copy />
89 )}
90 </InputGroupButton>
91 </InputGroupAddon>
92 </InputGroup>
93 </div>
94 )
95}
96Displays a descriptive label or info icon aligned with the input field.
1'use client'
2
3import { InfoIcon } from 'lucide-react'
4
5import {
6 InputGroup,
7 InputGroupAddon,
8 InputGroupButton,
9 InputGroupInput,
10} from '@/components/ui/input-group'
11import { Label } from '@/components/ui/label'
12import {
13 Tooltip,
14 TooltipContent,
15 TooltipProvider,
16 TooltipTrigger,
17} from '@/components/ui/tooltip'
18
19export function InputGroupWithLabel() {
20 return (
21 <TooltipProvider>
22 <div className="grid w-60 gap-4 sm:w-80">
23 <InputGroup>
24 <InputGroupAddon align="inline-start">
25 <Label
26 htmlFor="username"
27 className="text-sm font-medium"
28 >
29 Username
30 </Label>
31 </InputGroupAddon>
32 <InputGroupInput
33 id="username"
34 placeholder="Enter your username"
35 />
36 </InputGroup>
37
38 <InputGroup>
39 <InputGroupAddon
40 align="block-start"
41 className="items-center"
42 >
43 <div className="flex w-full items-center justify-between">
44 <Label
45 htmlFor="email"
46 className="text-sm font-medium"
47 >
48 Email address
49 </Label>
50 <Tooltip>
51 <TooltipTrigger asChild>
52 <InputGroupButton
53 size="icon-xs"
54 variant="ghost"
55 className="rounded-full"
56 aria-label="Email info"
57 >
58 <InfoIcon className="size-3.5" />
59 </InputGroupButton>
60 </TooltipTrigger>
61 <TooltipContent side="top" className="z-[60]">
62 <p className="text-xs">
63 Used for sending account updates and
64 notifications.
65 </p>
66 </TooltipContent>
67 </Tooltip>
68 </div>
69 </InputGroupAddon>
70 <InputGroupInput
71 id="email"
72 type="email"
73 placeholder="example@domain.com"
74 />
75 </InputGroup>
76 </div>
77 </TooltipProvider>
78 )
79}
80Shows a loading or processing state directly within the input group.
1'use client'
2
3import { RefreshCcw } from 'lucide-react'
4
5import {
6 InputGroup,
7 InputGroupAddon,
8 InputGroupInput,
9 InputGroupText,
10} from '@/components/ui/input-group'
11import { Spinner } from '@/components/ui/spinner'
12
13export function InputGroupWithSpinner() {
14 return (
15 <div className="grid w-60 gap-4 sm:w-80">
16 <InputGroup data-disabled>
17 <InputGroupInput placeholder="Searching users..." disabled />
18 <InputGroupAddon align="inline-end">
19 <Spinner />
20 </InputGroupAddon>
21 </InputGroup>
22
23 <InputGroup data-disabled>
24 <InputGroupAddon>
25 <RefreshCcw className="text-primary size-4 animate-spin" />
26 </InputGroupAddon>
27 <InputGroupInput placeholder="Syncing data..." disabled />
28 <InputGroupAddon align="inline-end">
29 <InputGroupText className="text-primary">
30 Wait...
31 </InputGroupText>
32 </InputGroupAddon>
33 </InputGroup>
34
35 <InputGroup data-disabled>
36 <InputGroupInput placeholder="Updating profile..." disabled />
37 <InputGroupAddon align="inline-end">
38 <InputGroupText>Updating</InputGroupText>
39 <Spinner />
40 </InputGroupAddon>
41 </InputGroup>
42
43 <InputGroup data-disabled>
44 <InputGroupAddon>
45 <Spinner />
46 </InputGroupAddon>
47 <InputGroupInput placeholder="Processing data..." disabled />
48 </InputGroup>
49 </div>
50 )
51}
52| Prop | Type | Default |
|---|---|---|
| align | inline-start,inline-end,block-start,block-end | inline-start |
| Prop | Type | Default |
|---|---|---|
| size | xs,sm,icon-xs,icon-sm | xs |
| variant | string | ghost |
| type | string | button |