For the complete documentation index, see llms.txt. Markdown variants are available by appending .md to documentation URLs. Homepage markdown is available at /llms.md/content.md. An agent skill is available at /.well-known/agent-skills/site-skill.md.

Avatar

The Avatar component from this design system, built on Base UI.

Installation

$ pnpm dlx shadcn@latest add @cobalt/avatar

Options

  • color is neutral (default), primary, blue, lime or pink. primary is a solid primary fill with the primary foreground.

Source

"use client";

import { Avatar as AvatarPrimitive } from "@base-ui/react/avatar";
import { cn } from "cn";
import * as React from "react";

function Avatar({
  className,
  size = "default",
  color = "neutral",
  ...props
}: AvatarPrimitive.Root.Props & {
  size?: "default" | "xs" | "sm" | "lg";
  color?: "neutral" | "primary" | "blue" | "lime" | "pink";
}) {
  return (
    <AvatarPrimitive.Root
      data-slot="avatar"
      data-size={size}
      data-color={color}
      className={cn(
        "group/avatar relative inline-flex size-8 shrink-0 items-center justify-center rounded-full text-center align-middle text-[16px] leading-[22px] font-semibold tracking-normal select-none transition-[width,height,font-size] duration-200 ease-[ease] motion-reduce:transition-none data-[size=xs]:size-5 data-[size=xs]:text-[10px] data-[size=xs]:leading-[15px] data-[size=sm]:size-6 data-[size=sm]:text-xs data-[size=sm]:leading-4 data-[size=lg]:size-9 data-[size=lg]:text-[18px] data-[size=lg]:leading-6",
        className
      )}
      {...props}
    />
  );
}

function AvatarImage({ className, ...props }: AvatarPrimitive.Image.Props) {
  return (
    <AvatarPrimitive.Image
      data-slot="avatar-image"
      className={cn(
        "aspect-square size-full rounded-full object-cover",
        className
      )}
      {...props}
    />
  );
}

function AvatarFallback({
  className,
  ...props
}: AvatarPrimitive.Fallback.Props) {
  return (
    <AvatarPrimitive.Fallback
      data-slot="avatar-fallback"
      className={cn(
        "flex size-full items-center justify-center overflow-hidden rounded-full bg-[var(--avatar-neutral-background,var(--muted))] text-[color:var(--foreground-secondary,var(--muted-foreground))] group-data-[color=primary]/avatar:bg-primary group-data-[color=primary]/avatar:text-primary-foreground group-data-[color=blue]/avatar:bg-[var(--avatar-blue-background,var(--muted))] group-data-[color=blue]/avatar:text-[color:var(--avatar-blue-foreground,var(--foreground))] group-data-[color=lime]/avatar:bg-[var(--avatar-lime-background,var(--muted))] group-data-[color=lime]/avatar:text-[color:var(--avatar-lime-foreground,var(--foreground))] group-data-[color=pink]/avatar:bg-[var(--avatar-pink-background,var(--muted))] group-data-[color=pink]/avatar:text-[color:var(--avatar-pink-foreground,var(--foreground))]",
        className
      )}
      {...props}
    />
  );
}

function AvatarBadge({ className, ...props }: React.ComponentProps<"span">) {
  return (
    <span
      data-slot="avatar-badge"
      className={cn(
        "absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground bg-blend-color ring-2 ring-background select-none",
        "group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden",
        "group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2",
        "group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2",
        className
      )}
      {...props}
    />
  );
}

function AvatarGroup({
  className,
  variant = "default",
  ...props
}: React.ComponentProps<"div"> & {
  /**
   * `raised` draws the separating ring in the fill of a raised card
   * (--surface-nested) instead of the page, for a group placed on a tile.
   */
  variant?: "default" | "raised";
}) {
  return (
    <div
      data-slot="avatar-group"
      data-variant={variant}
      className={cn(
        "group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2",
        variant === "raised"
          ? "*:data-[slot=avatar]:ring-[color:var(--surface-nested,var(--card))]"
          : "*:data-[slot=avatar]:ring-background",
        className
      )}
      {...props}
    />
  );
}

function AvatarGroupCount({
  className,
  ...props
}: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="avatar-group-count"
      className={cn(
        "relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-9 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3",
        className
      )}
      {...props}
    />
  );
}

export {
  Avatar,
  AvatarImage,
  AvatarFallback,
  AvatarGroup,
  AvatarGroupCount,
  AvatarBadge,
};