Skip to content
Lenso UI

User

Migration guide for User from HeroUI v2 to v3

The User component has been removed in HeroUI v3. Compose user displays manually using Avatar and text elements with Tailwind CSS classes.

Key Changes

1. Component Removal

v2: <User> component from @lenso/ui
v3: Manual composition using Avatar + text elements

2. Features Mapping

The v2 User component had the following features that need to be replaced:

v2 Featurev3 EquivalentNotes
name propText elementRender name as text or heading
description propText elementRender description as text
avatarProps propAvatar componentUse v3 Avatar component directly
isFocusable propManual focus handlingAdd tabIndex and focus styles if needed
classNames propTailwind classesApply classes directly to elements

Structure Changes

v2: User Component

In v2, User was a convenience component combining Avatar with name:

import { User } from "@lenso/ui";
export default function App() {  return (    <User      name="Junior Garcia"      avatarProps={{        src: "https://example.com/avatar.jpg",      }}    />  );}

v3: Manual Composition

In v3, compose user displays manually using Avatar and text elements:

import { Avatar } from "@lenso/ui";
export default function App() {  return (    <div className="inline-flex items-center gap-2">      <Avatar>        <Avatar.Image          src="https://example.com/avatar.jpg"          alt="Junior Garcia"        />        <Avatar.Fallback>JG</Avatar.Fallback>      </Avatar>      <span className="text-sm">Junior Garcia</span>    </div>  );}

Migration Examples

With Description

import { User } from "@lenso/ui";
<User  name="Junior Garcia"  description="Software Engineer"  avatarProps={{    src: "https://example.com/avatar.jpg",  }}/>

With Default Avatar (Initials)

import { User } from "@lenso/ui";
<User  name="Junior Garcia"  avatarProps={{    name: "Junior Garcia",    getInitials: (name) =>      name        .split(" ")        .map((n) => n[0])        .join(""),  }}/>
import { User, Link } from "@lenso/ui";
<User  name="Junior Garcia"  description={    <Link href="https://x.com/jrgarciadev" size="sm">      @jrgarciadev    </Link>  }  avatarProps={{    src: "https://example.com/avatar.jpg",  }}/>

Clickable User

import { User } from "@lenso/ui";
{/* Focusable */}<User  name="Junior Garcia"  isFocusable  avatarProps={{    src: "https://example.com/avatar.jpg",  }}/>
{/* As button */}<User  as="button"  name="Junior Garcia"  avatarProps={{    src: "https://example.com/avatar.jpg",  }}/>

Since User displays are commonly needed, here's a reusable component:

import { User } from "@lenso/ui";
<User  name="Junior Garcia"  description="Software Engineer"  avatarProps={{    src: "https://example.com/avatar.jpg",  }}/>

Styling Reference

The v2 User component used these base styles that you should replicate:

  • Base container: inline-flex items-center gap-2 rounded-sm
  • Wrapper (for name/description): inline-flex flex-col items-start
  • Name: text-sm (text-small)
  • Description: text-xs text-muted (text-tiny text-foreground-400)

Summary

  1. Component Removed: User component no longer exists in v3
  2. Import Change: Remove import { User } from "@lenso/ui"
  3. Manual Composition: Compose using Avatar + text elements
  4. Avatar Changes: Use v3 Avatar compound component pattern
  5. Styling: Apply Tailwind CSS classes directly
  6. Focus Handling: Implement focus styles manually if needed

Migration Steps

  1. Remove Import: Remove User from @lenso/ui imports
  2. Replace Component: Replace all <User> instances with manual composition
  3. Use Avatar: Use v3 Avatar component with compound pattern
  4. Add Text Elements: Add name and description as text elements
  5. Apply Styling: Use Tailwind CSS classes for layout and styling
  6. Handle Focus: Add focus styles if isFocusable was used
  7. Optional: Create reusable User component for your application

Common Patterns

User List

<div className="space-y-2">  {users.map((user) => (    <div key={user.id} className="inline-flex items-center gap-2">      <Avatar>        <Avatar.Image src={user.avatar} alt={user.name} />        <Avatar.Fallback>{getInitials(user.name)}</Avatar.Fallback>      </Avatar>      <div className="flex flex-col items-start">        <span className="text-sm">{user.name}</span>        {user.role && (          <span className="text-xs text-muted">{user.role}</span>        )}      </div>    </div>  ))}</div>

Clickable User

<button  className="inline-flex items-center gap-2 rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-focus hover:bg-default-100"  onClick={() => handleUserClick(user)}>  <Avatar>    <Avatar.Image src={user.avatar} alt={user.name} />    <Avatar.Fallback>{getInitials(user.name)}</Avatar.Fallback>  </Avatar>  <div className="flex flex-col items-start">    <span className="text-sm">{user.name}</span>    <span className="text-xs text-muted">{user.email}</span>  </div></button>