shadcn.io is an independent project built on shadcn/ui
Edit Profile opens Edit profile. A gradient cover has buttons to change or remove it, and Margaret Villard's photo overlaps the corner. The fields show Margaret, Villard, margaret-villard-69 with a check, a website prefixed https://, and a biography with characters left.
Use it to edit a profile without a settings page. The check does not look the name up. A longer editor fits a Sheet. In React, Ark UI does not save the profile.
Installation
Anatomy

Usage
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Edit Profile</Button>
</DialogTrigger>
<DialogContent className="gap-0 p-0 sm:max-w-2xl">
<DialogHeader className="px-6 py-4">
<DialogTitle>Edit profile</DialogTitle>
</DialogHeader>
<div className="relative">
<div className="h-40 bg-linear-to-r from-primary/30 via-primary/15 to-muted" />
<div className="absolute end-4 top-4 flex gap-2">
<Button
aria-label="Change cover image"
pill
size="icon-sm"
variant="secondary"
>
<ImageIcon aria-hidden="true" />
</Button>
<Button
aria-label="Remove cover image"
pill
size="icon-sm"
variant="secondary"
>
<XIcon aria-hidden="true" />
</Button>
</div>
<div className="absolute start-6 -bottom-12">
<Avatar className="size-24 ring-4 ring-background">
<AvatarImage
{/* The rest of the file is under Installation. */}FAQ
How do the image buttons upload?
They're icon buttons with an aria-label and no handler. Have each open a hidden file input with accept="image/*", preview the file, and upload it when people save.
Does the check mean the username is available?
It's a static text-success check in an InputGroupAddon. Check availability as people type, with a short debounce, and swap the icon for a spinner or an error while it runs.
How does the character counter work?
The textarea is controlled with maxLength of 200, and a FieldDescription under it shows 200 minus the current length.
How is the https:// prefix built?
An InputGroup with the InputGroupInput and an InputGroupAddon holding InputGroupText. The addon comes after the input in the markup, so clicking it focuses the input, and align="inline-start" shows it first.
API Reference
Dialog
Sets asChild. The rest is on the Dialog page.
Button
Sets variant="outline", aria-label="Change cover image", pill, size="icon-sm", variant="secondary" and aria-label="Remove cover image". The rest is on the Button page.
Avatar
Sets alt="Margaret Villard" and src="https://github.com/shadcn.png". The rest is on the Avatar page.
Field
No extra props in this demo. The rest is on the Field page.
Input
Sets defaultValue="Margaret", name="first-name", type="text", defaultValue="Villard" and name="last-name". The rest is on the Input page.
Input Group
Sets name="username", onChange={handleUsernameChange}, type="text", value={username}, align="inline-end" and defaultValue="www.margaret.com". The rest is on the Input Group page.
Textarea
Sets maxLength={maxBioLength}, name="bio", onChange={handleBioChange} and value={bio}. The rest is on the Textarea page.





