Inline Edit

Click-to-edit fields that transform from text to input on click.

Forms & Inputinlineeditclick-to-editinputtext

Dependencies

Other dependencies:

@/components/ui/input@/components/ui/button

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 } from 'react';
4import { Input } from '@/components/ui/input';
5import { Button } from '@/components/ui/button';
6import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
7import { Pencil, Check, X, User, Mail, Briefcase } from 'lucide-react';
8
9interface EditableFieldProps {
10 label: string;
11 value: string;
12 icon: React.ReactNode;
13 onSave: (value: string) => void;
14}
15
16function EditableField({ label, value, icon, onSave }: EditableFieldProps) {
17 const [isEditing, setIsEditing] = useState(false);
18 const [editValue, setEditValue] = useState(value);
19
20 const handleSave = () => {
21 if (editValue.trim()) {
22 onSave(editValue.trim());
23 setIsEditing(false);
24 }
25 };
26
27 const handleCancel = () => {
28 setEditValue(value);
29 setIsEditing(false);
30 };
31
32 return (
33 <div className={`flex items-center justify-between p-3 rounded-lg transition-colors \` +
34 `${isEditing ? 'bg-muted' : 'hover:bg-muted/50 group'}`}>
35 <div className="flex items-center gap-3">
36 <div className="p-2 bg-primary/10 rounded-lg text-primary">
37 {icon}
38 </div>
39 <div>
40 <p className="text-xs text-muted-foreground uppercase tracking-wide">{label}</p>
41 {isEditing ? (
42 <Input
43 value={editValue}
44 onChange={e => setEditValue(e.target.value)}
45 onKeyDown={e => {
46 if (e.key === 'Enter') handleSave();
47 if (e.key === 'Escape') handleCancel();
48 }}
49 className="h-7 w-48"
50 autoFocus
51 />
52 ) : (
53 <p className="font-medium">{value}</p>
54 )}
55 </div>
56 </div>
57 {isEditing ? (
58 <div className="flex items-center gap-1">
59 <Button size="sm" variant="ghost" className="h-7 w-7 p-0" onClick={handleSave}>
60 <Check className="w-4 h-4 text-green-500" />
61 </Button>
62 <Button size="sm" variant="ghost" className="h-7 w-7 p-0" onClick={handleCancel}>
63 <X className="w-4 h-4 text-red-500" />
64 </Button>
65 </div>
66 ) : (
67 <Button
68 size="sm"
69 variant="ghost"
70 className="h-7 w-7 p-0 opacity-0 group-hover:opacity-100"
71 onClick={() => setIsEditing(true)}
72 >
73 <Pencil className="w-4 h-4" />
74 </Button>
75 )}
76 </div>
77 );
78}
79
80export default function InlineEdit() {
81 const [fields, setFields] = useState({
82 name: 'Sarah Johnson',
83 email: 'sarah.johnson@example.com',
84 role: 'Senior Developer'
85 });
86
87 const updateField = (key: keyof typeof fields, value: string) => {
88 setFields(prev => ({ ...prev, [key]: value }));
89 };
90
91 return (
92 <Card className="w-full max-w-md mx-auto">
93 <CardHeader>
94 <CardTitle>User Profile</CardTitle>
95 </CardHeader>
96 <CardContent className="space-y-2">
97 <EditableField
98 label="Name"
99 value={fields.name}
100 icon={<User className="w-4 h-4" />}
101 onSave={value => updateField('name', value)}
102 />
103 <EditableField
104 label="Email"
105 value={fields.email}
106 icon={<Mail className="w-4 h-4" />}
107 onSave={value => updateField('email', value)}
108 />
109 <EditableField
110 label="Role"
111 value={fields.role}
112 icon={<Briefcase className="w-4 h-4" />}
113 onSave={value => updateField('role', value)}
114 />
115 </CardContent>
116 </Card>
117 );
118}

Related Forms & Input Components

Command Palette

Search for a command to run...