Avatar
React data-displayRound or rounded-square user image with a fallback that shows initials or an icon when the image is missing or fails to load. Sizes from xs to 2xl, optional status dot, and a group composition for stacked avatar lists.
Also available for Vue ->Installation
$ pnpm dlx shadcn@latest add https://react.uipkge.dev/r/react/avatar.json$ npx shadcn@latest add https://react.uipkge.dev/r/react/avatar.json$ yarn dlx shadcn@latest add https://react.uipkge.dev/r/react/avatar.json$ bunx shadcn@latest add https://react.uipkge.dev/r/react/avatar.json
Or with the named registry:
npx shadcn@latest add @uipkge-react/avatar
Examples
Props
| Name | Type / Values | Default | Required |
|---|---|---|---|
size | 'xs''sm''default''lg''xl''2xl' | default | optional |
rounded | 'none''sm''default''md''lg''xl''2xl''3xl''full' | default | optional |
color | 'default''primary''secondary''destructive''success''warning''info''error''muted' | default | optional |
variant | 'default''outlined''soft' | — | optional |
tile | boolean | false | optional |
disabled | boolean | false | optional |
loading | boolean | false | optional |
Dependencies
Used by
Files (3)
-
components/ui/avatar/avatar.tsx 5.1 kB
'use client' import * as React from 'react' import * as AvatarPrimitive from '@radix-ui/react-avatar' import { cn } from '@/lib/utils' import { avatarVariants, avatarFallbackVariants } from './avatar.variants' /* ------------------------------------------------------------------ */ /* Avatar (Root) */ /* ------------------------------------------------------------------ */ export interface AvatarProps extends Omit<React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>, 'color'> { size?: 'xs' | 'sm' | 'default' | 'lg' | 'xl' | '2xl' rounded?: 'none' | 'sm' | 'default' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full' color?: 'default' | 'primary' | 'secondary' | 'destructive' | 'success' | 'warning' | 'info' | 'error' | 'muted' variant?: 'default' | 'outlined' | 'soft' tile?: boolean disabled?: boolean loading?: boolean } const Avatar = React.forwardRef<React.ElementRef<typeof AvatarPrimitive.Root>, AvatarProps>( ({ className, size, rounded, color, variant, tile = false, disabled = false, loading = false, ...props }, ref) => ( <AvatarPrimitive.Root ref={ref} data-uipkge="" data-slot="avatar" className={cn( avatarVariants({ size, rounded, color, variant }), tile ? 'rounded-none' : '', disabled ? 'opacity-50 cursor-not-allowed' : '', loading ? 'animate-pulse' : '', className, )} {...props} /> ), ) Avatar.displayName = 'Avatar' /* ------------------------------------------------------------------ */ /* AvatarImage */ /* ------------------------------------------------------------------ */ const AvatarImage = React.forwardRef< React.ElementRef<typeof AvatarPrimitive.Image>, React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image> >(({ className, ...props }, ref) => ( <AvatarPrimitive.Image ref={ref} data-uipkge="" data-slot="avatar-image" className={cn('aspect-square size-full object-cover', className)} {...props} /> )) AvatarImage.displayName = 'AvatarImage' /* ------------------------------------------------------------------ */ /* AvatarFallback */ /* ------------------------------------------------------------------ */ export interface AvatarFallbackProps extends Omit<React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>, 'color'> { size?: 'xs' | 'sm' | 'default' | 'lg' | 'xl' | '2xl' color?: 'default' | 'primary' | 'secondary' | 'destructive' | 'success' | 'warning' | 'info' | 'error' | 'muted' text?: string } const AvatarFallback = React.forwardRef< React.ElementRef<typeof AvatarPrimitive.Fallback>, AvatarFallbackProps >(({ className, size = 'default', color = 'default', text, children, ...props }, ref) => ( <AvatarPrimitive.Fallback ref={ref} data-uipkge="" data-slot="avatar-fallback" className={cn(avatarFallbackVariants({ size, color }), className)} {...props} > {text ?? children} </AvatarPrimitive.Fallback> )) AvatarFallback.displayName = 'AvatarFallback' /* ------------------------------------------------------------------ */ /* AvatarGroup — custom layout wrapper (not a Radix primitive) */ /* ------------------------------------------------------------------ */ const overflowSizeClasses: Record<NonNullable<AvatarGroupProps['size']>, string> = { xs: 'size-4 text-[8px]', sm: 'size-6 text-xs', default: 'size-8 text-sm', lg: 'size-12 text-base', xl: 'size-16 text-lg', '2xl': 'size-20 text-xl', } export interface AvatarGroupProps extends React.HTMLAttributes<HTMLDivElement> { max?: number overlap?: boolean size?: 'xs' | 'sm' | 'default' | 'lg' | 'xl' | '2xl' total?: number /** Custom overflow indicator. Receives the hidden count; replaces the * default `+N` badge when provided. */ overflow?: (count: number) => React.ReactNode } const AvatarGroup = React.forwardRef<HTMLDivElement, AvatarGroupProps>( ({ className, max, overlap = true, size = 'default', total, overflow, children, ...props }, ref) => { const items = React.Children.toArray(children) const count = items.length const showOverflow = max != null && count > max const visible = showOverflow ? items.slice(0, max) : items const overflowCount = count - (max ?? count) + 1 return ( <div ref={ref} data-uipkge="" data-slot="avatar-group" className={cn('flex items-center', overlap ? '-space-x-2' : 'gap-1', className)} {...props} > {visible} {showOverflow ? ( <div className={cn( 'bg-muted ring-background relative flex shrink-0 overflow-hidden rounded-full ring-2', overflowSizeClasses[size], )} > {overflow ? ( overflow(overflowCount) ) : ( <span className="flex size-full items-center justify-center font-medium">+{overflowCount}</span> )} </div> ) : null} </div> ) }, ) AvatarGroup.displayName = 'AvatarGroup' export { Avatar, AvatarImage, AvatarFallback, AvatarGroup } -
components/ui/avatar/avatar.variants.ts 3.4 kB
import type { VariantProps } from 'class-variance-authority' import { cva } from 'class-variance-authority' /** * Variant definitions live in their own file (rather than the package * `index.ts` or inline in the SFC) so `Avatar.vue` / `AvatarFallback.vue` * can `import { avatarVariants } from './avatar.variants'` without * creating a circular dependency back through the index. The circular * form caused intermittent `$setup.avatarVariants is not a function` * errors during dev SSR. */ export const avatarVariants = cva('relative flex shrink-0 overflow-hidden', { variants: { size: { xs: 'size-4', sm: 'size-6', default: 'size-8', lg: 'size-12', xl: 'size-16', '2xl': 'size-20', }, rounded: { none: 'rounded-none', sm: 'rounded-sm', default: 'rounded-full', md: 'rounded-md', lg: 'rounded-lg', xl: 'rounded-xl', '2xl': 'rounded-2xl', '3xl': 'rounded-3xl', full: 'rounded-full', }, color: { default: '', primary: 'bg-primary text-primary-foreground', secondary: 'bg-secondary text-secondary-foreground', destructive: 'bg-destructive text-destructive-foreground', success: 'bg-[var(--success)] text-white dark:text-black', warning: 'bg-[var(--warning)] text-black', info: 'bg-[var(--info)] text-white dark:text-black', error: 'bg-destructive text-white dark:text-black', muted: 'bg-muted text-muted-foreground', }, variant: { default: '', outlined: 'border-2 border-current', soft: 'bg-opacity-20', }, }, compoundVariants: [ { color: 'primary', variant: 'soft', class: 'bg-primary/20 text-primary' }, { color: 'secondary', variant: 'soft', class: 'bg-secondary/20 text-secondary-foreground' }, { color: 'destructive', variant: 'soft', class: 'bg-destructive/20 text-destructive' }, { color: 'success', variant: 'soft', class: 'bg-[var(--success)]/20 text-[var(--success)]' }, { color: 'warning', variant: 'soft', class: 'bg-[var(--warning)]/20 text-[var(--warning)]' }, { color: 'info', variant: 'soft', class: 'bg-[var(--info)]/20 text-[var(--info)]' }, { color: 'error', variant: 'soft', class: 'bg-destructive/20 text-destructive' }, ], defaultVariants: { size: 'default', rounded: 'default', color: 'default', }, }) export type AvatarVariants = VariantProps<typeof avatarVariants> export const avatarFallbackVariants = cva( 'flex size-full items-center justify-center rounded-full bg-muted font-medium', { variants: { size: { xs: 'text-[8px]', sm: 'text-xs', default: 'text-sm', lg: 'text-base', xl: 'text-lg', '2xl': 'text-xl', }, color: { default: '', primary: 'bg-primary text-primary-foreground', secondary: 'bg-secondary text-secondary-foreground', destructive: 'bg-destructive text-destructive-foreground', success: 'bg-[var(--success)] text-white dark:text-black', warning: 'bg-[var(--warning)] text-black', info: 'bg-[var(--info)] text-white dark:text-black', error: 'bg-destructive text-white dark:text-black', muted: 'bg-muted text-muted-foreground', }, }, defaultVariants: { size: 'default', color: 'default', }, }, ) export type AvatarFallbackVariants = VariantProps<typeof avatarFallbackVariants> -
components/ui/avatar/index.ts 0.4 kB
export { Avatar, AvatarImage, AvatarFallback, AvatarGroup, type AvatarProps, type AvatarFallbackProps, type AvatarGroupProps } from './avatar' // Re-export variant API from the sibling file (kept separate to mirror the // Vue registry convention and avoid a component <-> index circular import). export { avatarVariants, avatarFallbackVariants, type AvatarVariants, type AvatarFallbackVariants, } from './avatar.variants'
Raw manifest: https://react.uipkge.dev/r/react/avatar.json