Tag Input

An input that creates tag badges on Enter press with remove functionality.

Forms & Inputtagsinputbadgeschipsmulti-select

Dependencies

Other dependencies:

@/components/ui/badge@/components/ui/input@/components/ui/card@/components/ui/label

How to use this component

Copy the code below into your project. Make sure you have the required shadcn/ui dependencies installed. Then import and use the component in your pages or layouts.

Code

1"use client";
2
3import { useState, KeyboardEvent } from 'react';
4import { Badge } from '@/components/ui/badge';
5import { Input } from '@/components/ui/input';
6import { Card, CardContent } from '@/components/ui/card';
7import { Label } from '@/components/ui/label';
8import { X } from 'lucide-react';
9
10export default function TagInput() {
11 const [tags, setTags] = useState(['React', 'TypeScript', 'Tailwind']);
12 const [inputValue, setInputValue] = useState('');
13 const maxTags = 10;
14
15 const addTag = () => {
16 const trimmed = inputValue.trim();
17 if (trimmed && !tags.includes(trimmed) && tags.length < maxTags) {
18 setTags(prev => [...prev, trimmed]);
19 setInputValue('');
20 }
21 };
22
23 const removeTag = (tagToRemove: string) => {
24 setTags(prev => prev.filter(tag => tag !== tagToRemove));
25 };
26
27 const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
28 if (e.key === 'Enter') {
29 e.preventDefault();
30 addTag();
31 } else if (e.key === 'Backspace' && !inputValue && tags.length > 0) {
32 removeTag(tags[tags.length - 1]);
33 }
34 };
35
36 return (
37 <Card className="w-full max-w-md mx-auto">
38 <CardContent className="p-6 space-y-4">
39 <div>
40 <Label htmlFor="tags">Tags</Label>
41 <div className="mt-2 flex flex-wrap items-center gap-2 p-2 border rounded-md min-h-[42px] bg-background">
42 {tags.map(tag => (
43 <Badge key={tag} variant="secondary" className="gap-1 pr-1">
44 {tag}
45 <button
46 onClick={() => removeTag(tag)}
47 className="ml-1 rounded-full hover:bg-muted-foreground/20 p-0.5"
48 >
49 <X className="w-3 h-3" />
50 </button>
51 </Badge>
52 ))}
53 <Input
54 id="tags"
55 value={inputValue}
56 onChange={e => setInputValue(e.target.value)}
57 onKeyDown={handleKeyDown}
58 placeholder={tags.length === 0 ? 'Type and press Enter...' : ''}
59 className="border-0 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 px-0 h-6 flex-1 min-w-[120px]"
60 />
61 </div>
62 </div>
63
64 <div className="flex items-center justify-between text-sm">
65 <p className="text-muted-foreground">Press Enter to add a tag</p>
66 <p className={`text-muted-foreground \` +
67 `${tags.length >= maxTags ? 'text-red-500' : ''}`}>
68 {tags.length}/{maxTags}
69 </p>
70 </div>
71
72 {tags.length >= maxTags && (
73 <p className="text-sm text-red-500">Maximum number of tags reached</p>
74 )}
75 </CardContent>
76 </Card>
77 );
78}

Related Forms & Input Components

Command Palette

Search for a command to run...