Simple avatar wrapper
import { Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage } from '@/components/ui/avatar'
...import { Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage } from '@/components/ui/avatar'
export default function AvatarDemoExample() {
return (
<div class="flex flex-wrap items-center gap-6 md:gap-12">
<Avatar><AvatarImage class="grayscale" src="https://github.com/shadcn.png" alt="@shadcn" /><AvatarFallback>CN</AvatarFallback></Avatar>
<Avatar><AvatarImage src="https://github.com/evilrabbit.png" alt="@evilrabbit" /><AvatarFallback>ER</AvatarFallback><AvatarBadge class="bg-green-600 dark:bg-green-800" /></Avatar>
<AvatarGroup class="grayscale">
<Avatar><AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" /><AvatarFallback>CN</AvatarFallback></Avatar>
<Avatar><AvatarImage src="https://github.com/maxleiter.png" alt="@maxleiter" /><AvatarFallback>LR</AvatarFallback></Avatar>
<Avatar><AvatarImage src="https://github.com/evilrabbit.png" alt="@evilrabbit" /><AvatarFallback>ER</AvatarFallback></Avatar>
<AvatarGroupCount>+3</AvatarGroupCount>
</AvatarGroup>
</div>
)
}
Installation
npx @fictjs/shadcn@latest add avatarInstall the runtime dependencies:
npm install @fictjs/radix-uiCopy the Fict shadcn component into your project.
Source
components/ui/avatar.tsx
src/components/ui/avatar.tsx
import { Avatar as AvatarPrimitive } from '@fictjs/radix-ui'
import { cn } from '@/lib/cn'
type GenericProps = {
class?: string
children?: unknown
[key: string]: unknown
}
type AvatarProps = GenericProps & {
size?: 'default' | 'sm' | 'lg'
}
export function Avatar(props: AvatarProps) {
const { class: className, size = 'default', ...rest } = props
return (
<AvatarPrimitive.Root
data-slot='avatar'
data-size={size}
class={cn(
'group/avatar relative flex shrink-0 select-none rounded-full',
size === 'sm' ? 'size-6' : size === 'lg' ? 'size-10' : 'size-8',
className,
)}
{...rest}
/>
)
}
export function AvatarImage(props: GenericProps) {
const { class: className, ...rest } = props
return <AvatarPrimitive.Image data-slot='avatar-image' class={cn('aspect-square size-full rounded-full object-cover', className)} {...rest} />
}
export function AvatarFallback(props: GenericProps) {
const { class: className, ...rest } = props
return <AvatarPrimitive.Fallback data-slot='avatar-fallback' class={cn('flex size-full items-center justify-center rounded-full bg-muted text-sm group-data-[size=sm]/avatar:text-xs', className)} {...rest} />
}
export function AvatarBadge(props: GenericProps) {
const { class: className, ...rest } = props
return <span data-slot='avatar-badge' class={cn('absolute bottom-0 right-0 z-10 inline-flex size-2.5 items-center justify-center rounded-full ring-2 ring-background [&_svg]:size-2', className)} {...rest} />
}
export function AvatarGroup(props: GenericProps) {
const { class: className, ...rest } = props
return <div data-slot='avatar-group' class={cn('flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background', className)} {...rest} />
}
export function AvatarGroupCount(props: GenericProps) {
const { class: className, ...rest } = props
return <div data-slot='avatar-group-count' class={cn('relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-xs ring-2 ring-background [&_svg]:size-4', className)} {...rest} />
}
Usage
Examples
Basic
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
...import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
export default function AvatarBasicExample() {
return <Avatar><AvatarImage class="grayscale" src="https://github.com/shadcn.png" alt="@shadcn" /><AvatarFallback>CN</AvatarFallback></Avatar>
}
Badge
import { Avatar, AvatarBadge, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
...import { Avatar, AvatarBadge, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
export default function AvatarBadgeExample() {
return <Avatar><AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" /><AvatarFallback>CN</AvatarFallback><AvatarBadge class="bg-green-600 dark:bg-green-800" /></Avatar>
}
Badge Icon
import { Avatar, AvatarBadge, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
...import { Avatar, AvatarBadge, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
function PlusIcon() {
return <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" aria-hidden="true"><path d="M12 5v14M5 12h14" /></svg>
}
export default function AvatarBadgeIconExample() {
return <Avatar><AvatarImage class="grayscale" src="https://github.com/pranathip.png" alt="@pranathip" /><AvatarFallback>PP</AvatarFallback><AvatarBadge><PlusIcon /></AvatarBadge></Avatar>
}
Group
import { Avatar, AvatarFallback, AvatarGroup, AvatarImage } from '@/components/ui/avatar'
...import { Avatar, AvatarFallback, AvatarGroup, AvatarImage } from '@/components/ui/avatar'
export default function AvatarGroupExample() {
return (
<AvatarGroup class="grayscale">
<Avatar><AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" /><AvatarFallback>CN</AvatarFallback></Avatar>
<Avatar><AvatarImage src="https://github.com/maxleiter.png" alt="@maxleiter" /><AvatarFallback>LR</AvatarFallback></Avatar>
<Avatar><AvatarImage src="https://github.com/evilrabbit.png" alt="@evilrabbit" /><AvatarFallback>ER</AvatarFallback></Avatar>
</AvatarGroup>
)
}
Group Count
import { Avatar, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage } from '@/components/ui/avatar'
...import { Avatar, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage } from '@/components/ui/avatar'
export default function AvatarGroupCountExample() {
return (
<AvatarGroup class="grayscale">
<Avatar><AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" /><AvatarFallback>CN</AvatarFallback></Avatar>
<Avatar><AvatarImage src="https://github.com/maxleiter.png" alt="@maxleiter" /><AvatarFallback>LR</AvatarFallback></Avatar>
<Avatar><AvatarImage src="https://github.com/evilrabbit.png" alt="@evilrabbit" /><AvatarFallback>ER</AvatarFallback></Avatar>
<AvatarGroupCount>+3</AvatarGroupCount>
</AvatarGroup>
)
}
Group Count Icon
import { Avatar, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage } from '@/components/ui/avatar'
...import { Avatar, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage } from '@/components/ui/avatar'
function PlusIcon() {
return <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M12 5v14M5 12h14" /></svg>
}
export default function AvatarGroupCountIconExample() {
return (
<AvatarGroup class="grayscale">
<Avatar><AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" /><AvatarFallback>CN</AvatarFallback></Avatar>
<Avatar><AvatarImage src="https://github.com/maxleiter.png" alt="@maxleiter" /><AvatarFallback>LR</AvatarFallback></Avatar>
<Avatar><AvatarImage src="https://github.com/evilrabbit.png" alt="@evilrabbit" /><AvatarFallback>ER</AvatarFallback></Avatar>
<AvatarGroupCount><PlusIcon /></AvatarGroupCount>
</AvatarGroup>
)
}
Size
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
...import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
export default function AvatarSizeExample() {
return (
<div class="flex items-center gap-2 grayscale">
<Avatar size="sm"><AvatarImage src="https://github.com/shadcn.png" alt="@shadcn small" /><AvatarFallback>CN</AvatarFallback></Avatar>
<Avatar><AvatarImage src="https://github.com/shadcn.png" alt="@shadcn default" /><AvatarFallback>CN</AvatarFallback></Avatar>
<Avatar size="lg"><AvatarImage src="https://github.com/shadcn.png" alt="@shadcn large" /><AvatarFallback>CN</AvatarFallback></Avatar>
</div>
)
}
Dropdown
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Button } from '@/components/ui/button'
...import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Button } from '@/components/ui/button'
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
export default function AvatarDropdownExample() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild><Button variant="ghost" size="icon" class="rounded-full" aria-label="Open user menu"><Avatar><AvatarImage src="https://github.com/shadcn.png" alt="shadcn" /><AvatarFallback>CN</AvatarFallback></Avatar></Button></DropdownMenuTrigger>
<DropdownMenuContent class="w-32">
<DropdownMenuItem>Profile</DropdownMenuItem><DropdownMenuItem>Billing</DropdownMenuItem><DropdownMenuItem>Settings</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem class="text-destructive focus:text-destructive">Log out</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}
Rtl
import { Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage } from '@/components/ui/avatar'
...import { Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage } from '@/components/ui/avatar'
const translations = { ar: '+٣', he: '+3', en: '+3' } as const
export default function AvatarRtlExample() {
let language = $state<keyof typeof translations>('ar')
const direction = () => language === 'en' ? 'ltr' : 'rtl'
return (
<div class="grid gap-4">
<select value={language} onChange={event => { language = event.currentTarget.value as keyof typeof translations }}><option value="ar">Arabic (العربية)</option><option value="he">Hebrew (עברית)</option><option value="en">English</option></select>
<div class="flex flex-wrap items-center gap-6 md:gap-12" dir={direction()}>
<Avatar><AvatarImage class="grayscale" src="https://github.com/shadcn.png" alt="@shadcn" /><AvatarFallback>CN</AvatarFallback></Avatar>
<Avatar><AvatarImage src="https://github.com/evilrabbit.png" alt="@evilrabbit" /><AvatarFallback>ER</AvatarFallback><AvatarBadge class="bg-green-600 dark:bg-green-800" /></Avatar>
<AvatarGroup class="grayscale">
<Avatar><AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" /><AvatarFallback>CN</AvatarFallback></Avatar>
<Avatar><AvatarImage src="https://github.com/maxleiter.png" alt="@maxleiter" /><AvatarFallback>LR</AvatarFallback></Avatar>
<Avatar><AvatarImage src="https://github.com/evilrabbit.png" alt="@evilrabbit" /><AvatarFallback>ER</AvatarFallback></Avatar>
<AvatarGroupCount>{translations[language]}</AvatarGroupCount>
</AvatarGroup>
</div>
</div>
)
}