Avatar

An image element with a fallback for representing the user.

MIMIMI

Installation

Install the primitive and Copy-Paste the component code in a .tsx file.

npm install @radix-ui/react-avatar
import * as AvatarPrimitive from '@radix-ui/react-avatar';
import React from "react";
import { avatar, fallback, image, type AvatarRootProps, type AvatarFallbackProps } from "@tailus/themer";

const AvatarRoot = React.forwardRef<
  React.ElementRef<typeof AvatarPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root> & AvatarRootProps
>(({className, size="md", status="online", bottomStatus=false, topStatus=false, ...props}, ref) => {
  return (
    <AvatarPrimitive.Root
      {...props}
      ref={ref}
      className={avatar({size, status: status && status, topStatus, bottomStatus ,className})}
    />
  );
});

const AvatarFallback = React.forwardRef<
  React.ElementRef<typeof AvatarPrimitive.Fallback>,
  React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback> & AvatarFallbackProps
>(({className, variant = "solid", intent="primary", ...props}, ref) => {
  return (
    <AvatarPrimitive.Fallback
      {...props}
      ref={ref}
      className={fallback[variant]({intent, className})}
    />
  );
});

const AvatarImage = React.forwardRef<
  React.ElementRef<typeof AvatarPrimitive.Image>,
  React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
>(({className, ...props}, ref) => {
  return (
    <AvatarPrimitive.Image
      {...props}
      ref={ref}
      className={image({className})}
    />
  );
});

export default {
  Root: AvatarRoot,
  Fallback: AvatarFallback,
  Image: AvatarImage,
}

export {
  AvatarRoot,
  AvatarFallback,
  AvatarImage,
}

Usage

Import the Avatar parts you need to use in your component and build your Avatar.

import Avatar from "@tailus-ui/Avatar";
export const MyComponent = () => {
    <Avatar.Root>
        <Avatar.Image />
        <Avatar.Fallback />
    </Avatar.Root>
}

Reference

Root

The parent container of the Avatar component

Prop
Type
Default
size
enum
md
status
enum
-
topStatus
boolean
false
bottomStatus
boolean
false

Fallback

An element that renders when the image hasn’t loaded.

Prop
Type
Default
variant
enum
solid
intent
enum
primary

Examples

Colors

SolidABABABABABABABAB
SoftABABABABABABABAB
import Avatar from "@tailus-ui/Avatar"
import { type AvatarFallbackProps } from "@tailus/themer"

const intents:AvatarFallbackProps["intent"][] = ["primary", "secondary", "accent", "danger", "success", "warning", "info", "gray"]

export const Colors = () => {
    return (
        <div className="flex gap-x-4">
            {
                intents.map((intent, index) => {
                    return (
                        <Avatar.Root key={index}>
                            <Avatar.Fallback children="AB" intent={intent} />
                        </Avatar.Root>
                    )
                })
            }
        </div>
    )
}

Sizes

MI

xxs

MI

xs

MI

sm

MI

md

MI

lg

MI

xl

MI

2xl

MI

3xl

import Avatar from "@tailus-ui/Avatar"
import { type AvatarRootProps } from "@tailus/themer"
const sizes:AvatarRootProps["size"][] = ["xxs", "xs", "sm", "md", "lg", "xl", "2xl", "3xl"]

export const Sizes = () => {
    return (
        <div className="flex flex-wrap gap-4 items-end">
            {
                sizes.map((size, index) => {
                    return (
                        <Avatar.Root size={size} key={index}>
                            <Avatar.Image src="https://pbs.twimg.com/profile_images/1767582956082561024/TLJvxR_V_400x400.jpg" width={400} height={400} loading="lazy" />
                            <Avatar.Fallback className="text-sm" children="MI" />
                        </Avatar.Root>
                    )
                })
            }
        </div>
    )
}

Status

online

offline

away

busy

Top

MIMIMIMI

Bottom

MIMIMIMI
import { Caption } from "@components/typography"
import Avatar from "@tailus-ui/Avatar"
import { type AvatarRootProps } from "@tailus/themer"
const statuses: AvatarRootProps["status"][] = ["online", "offline", "away", "busy"]

export const AStatus = () => {
    return (
        <div className="flex items-end gap-12 py-6">
            <div className="space-y-4 -mr-6">
                {
                    statuses.map((status, index) => {
                        return (
                            <div className="h-9 flex items-center" key={index}>
                                <Caption size="sm">{status}</Caption>
                            </div>
                        )
                    })
                }
            </div>
            <div className="space-y-4">
                <Caption size="sm">Top</Caption>
                {
                    statuses.map((status, index) => {
                        return (
                            <Avatar.Root key={index} status={status} topStatus>
                                <Avatar.Image src="https://pbs.twimg.com/profile_images/1767582956082561024/TLJvxR_V_400x400.jpg" width={400} height={400} loading="lazy" />
                                <Avatar.Fallback className="text-sm" children="MI" />
                            </Avatar.Root>
                        )
                    })
                }
            </div>
            <div className="space-y-4">
                <Caption size="sm">Bottom</Caption>
                {
                    statuses.map((status, index) => {
                        return (
                            <Avatar.Root key={index} status={status} bottomStatus>
                                <Avatar.Image src="https://pbs.twimg.com/profile_images/1767582956082561024/TLJvxR_V_400x400.jpg" width={400} height={400} loading="lazy" />
                                <Avatar.Fallback className="text-sm" children="MI" />
                            </Avatar.Root>
                        )
                    })
                }
            </div>
        </div>
    )
}

Stacked Avatars

A collection of overlaid avatars with a transparent background, ensuring seamless integration with any backdrop, including gradients.

BNGLMITB+2
// Stacked.tsx

import Avatar from "@tailus-ui/Avatar"
import "styles/avatar-mask.css"
import "@styles/avatar-mask.css"
import { type AvatarFallbackProps } from "@tailus/themer"

export interface Person {
    name?: string,
    img: string,
    intent: AvatarFallbackProps["intent"],
    initials: string,
}

export const persons:Person[] = []

export const Stack = () => {
    return (
        <div className="flex -space-x-[3px]">
            {
                persons.map((person, index) => {
                    return (
                        <Avatar.Root size="sm" className="avatar-mask" key={index}>
                            <Avatar.Image src={person.img} alt={person.name} />
                            <Avatar.Fallback variant="soft" intent={person.intent}>
                                {person.initials}
                            </Avatar.Fallback>
                        </Avatar.Root>
                    )
                })
            }
        </div>
    )
}
// avatar-mask.svg

<svg viewBox="0 0 86 100" fill="none" xmlns="http://www.w3.org/2000/svg">
    <path d="M50 0C63.8501 0 76.3848 5.63135 85.4395 14.729C77.0806 24.0981 72 36.4561 72 50C72 63.5439 77.0806 75.9019 85.4395 85.271C76.3848 94.3687 63.8501 100 50 100C22.3857 100 0 77.6143 0 50C0 22.3857 22.3857 0 50 0Z" fill="#D9D9D9" style="fill:#D9D9D9;fill:color(display-p3 0.8510 0.8510 0.8510);fill-opacity:1;"/>
</svg>
// avatar-mask.css

@layer utilities {
    .avatar-mask {
        -webkit-mask-image: url('/avatar-mask.svg');
        mask-image: url('/avatar-mask.svg');
        mask-size: cover;
        -webkit-mask-size: cover;
        mask-repeat: no-repeat;
        -webkit-mask-repeat: no-repeat;
        -webkit-mask-position: center;
        mask-position: center;
    }
    .avatar-mask-none {
        -webkit-mask-image: none;
        mask-image: none;
    }
}