Skip to content
Drivn
5 min read

How to Add an Avatar to a React App

Step-by-step guide to adding a copy-and-own Avatar to any React app with the Drivn CLI — image, initials fallback, four sizes, zero runtime dependencies.

Every app with user accounts eventually needs an avatar, and the first attempt is usually a bare <img> with rounded-full on it. That works until the first user without a photo signs up and the layout shows an empty or broken circle. Then come the patches: a conditional for the missing image, a span for initials, a background color so the initials are readable, and three different size classNames scattered across the codebase. What started as one line quietly becomes an unmaintained mini-component duplicated in four files.

The cleaner path is a single Avatar you own. Drivn's CLI writes one into your repo — roughly forty lines of pure React and Tailwind with no runtime package and no Radix primitive. It takes src, alt, fallback, and size, renders the image when a URL exists, and otherwise shows the first two characters of the fallback string, uppercased, on a brand gradient. Four size presets — sm, md, lg, xl — replace the scattered width classes.

This guide adds the Avatar to an existing React app in about ten minutes: check prerequisites, install via the CLI, render it with an image and an initials fallback, pick sizes, and customize the gradient. The steps are identical in Vite, Next.js, Remix, or any React framework with Tailwind. For App Router specifics see the Next.js Avatar guide; for live patterns see the Avatar examples.

Prerequisites

Before installing the Avatar, confirm your React project has the three things Drivn assumes: Tailwind CSS v4 processing your styles, TypeScript configured — the component ships as a .tsx file and its size prop type is derived with keyof typeof, so TypeScript is required, not optional — and a @/ path alias pointing at your source directory. Projects scaffolded with create-next-app, npm create vite, or npx drivn@latest create have all three already. For a hand-rolled setup, check compilerOptions.paths in your tsconfig.json; the installation page lists the minimal config. The Avatar reads the primary and secondary color tokens for its fallback gradient, so make sure your Tailwind theme defines them — the installation page includes the token block to copy.

Step 1 — Install the Avatar via the CLI

Run the CLI from your project root to add the Avatar source file. The command prompts once for an install directory, defaulting to src/components/ui/, then writes avatar.tsx. Nothing is added to package.json — the component imports only React and the local cn helper, and it renders no icon, so there is no lucide-react to install either. The CLI docs cover flags for monorepos and non-standard layouts, plus adding several components in one command. After the file lands you own it: future Drivn releases never overwrite installed components, so every customization you make in the next steps is permanent. Commit the untouched file first to keep a clean baseline.

1# add the Avatar to your existing React project
2npx drivn add avatar

Step 2 — Render it with an image and a fallback

Import Avatar from your UI directory and pass src for the photo, alt for screen readers, and fallback for the initials. The component is a single div that conditionally renders either an <img> with object-cover or a span containing fallback?.slice(0, 2).toUpperCase() — so when src is undefined, null, or an empty string, the initials appear automatically with no null-check wrapper at the call site. Drive src straight from your user record's photo field and pass the display name as fallback: "Jane Doe" renders "JA", while an explicit "JD" renders as-is. The component holds no state and works in server components and static pages alike. The full prop table is in the Avatar docs.

1import { Avatar } from '@/components/ui/avatar'
2
3export function CommentHeader() {
4 return (
5 <div className="flex items-center gap-2">
6 <Avatar src="/users/jane.jpg" alt="Jane Doe" fallback="JD" />
7 <span className="text-sm font-medium">Jane Doe</span>
8 </div>
9 )
10}
11
12// No photo yet — initials render automatically
13<Avatar fallback="Jane Doe" />

Step 3 — Pick a size preset

The size prop accepts four presets mapped in the component's styles.sizes object: sm (32 px) for dense lists and table cells, md (40 px, the default) for comment threads and headers, lg (48 px) for profile cards, and xl (64 px) for account pages where the picture carries identity weight. Each preset pairs a width and height with a matching text size, so initials scale with the circle instead of floating in it. The prop type is keyof typeof styles.sizes, which means TypeScript autocompletes the four names and flags a typo at compile time. Mixing sizes across an app requires no className at any call site — pass size="sm" in the table and size="xl" on the profile page and both stay consistent.

1// src/components/ui/avatar.tsx — size presets
2sizes: {
3 sm: 'w-8 h-8 text-xs',
4 md: 'w-10 h-10 text-sm',
5 lg: 'w-12 h-12 text-base',
6 xl: 'w-16 h-16 text-lg',
7}
8
9// at the call site
10<Avatar fallback="JD" size="sm" />
11<Avatar fallback="JD" size="xl" />

Step 4 — Customize the gradient and shape

The Avatar's look lives in styles.base: a relative inline-flex container, rounded-full with overflow-hidden, and a bg-gradient-to-br from-primary to-secondary that shows behind initials and during image load. Your className merges last through cn, so per-instance overrides win — rounded-lg turns one avatar into a rounded square because tailwind-merge resolves the radius conflict, and a ring-2 ring-background adds the halo used in overlapping groups. To change every avatar at once, edit the base string in the source: swap the gradient for a flat bg-muted, or tighten the radius app-wide. Because the gradient reads the primary and secondary tokens, a rebrand through the theming page recolors all fallbacks without touching the file.

1// src/components/ui/avatar.tsx — base styles
2base: cn(
3 'relative inline-flex items-center justify-center',
4 'rounded-full overflow-hidden',
5 'bg-gradient-to-br from-primary to-secondary'
6),
7
8// per-instance override — rounded square
9<Avatar fallback="JD" className="rounded-lg" />
Get started

Install Drivn in one command

Copy the source into your project and own every line. Zero runtime dependencies, pure React + Tailwind.

Follow Drivn updates
New components, improvements, and guides every release.
Enjoying Drivn?
Star the repo on GitHub to follow new component releases.
Star →

Frequently asked questions

Yes. The Avatar depends on nothing framework-specific — no router, no Next.js API, no server feature. Set up TypeScript and Tailwind v4 in your Vite or CRA project, make sure the @/ path alias resolves, then run npx drivn add avatar. The same source file works unchanged across Vite, Next.js, Remix, and any other React environment that renders to the DOM.

The component switches on whether src is truthy, not on whether the image loads — so a URL that resolves to a 404 still renders the <img> element and the browser shows a broken image. To fall back on load errors too, add a const [imgError, setImgError] = React.useState(false) to the component, set it from the img's onError, and render the initials when either !src or imgError is true. The file is yours after install, so the edit is permanent.

It renders fallback?.slice(0, 2).toUpperCase() — the first two characters of whatever string you pass, uppercased. Passing a full name like "Jane Doe" therefore renders "JA", not "JD"; pass the two-letter code explicitly if you want classic first-plus-last initials. Omitting the prop entirely renders an empty gradient circle, which some teams use as an anonymous-user placeholder.

Yes — pass className="rounded-lg" for a rounded square or className="rounded-none" for sharp corners. The cn helper uses tailwind-merge, which resolves the conflict between your class and the component's base rounded-full, so the override needs no source edit. To make squares the default everywhere, change rounded-full in styles.base inside src/components/ui/avatar.tsx once.