<AvatarRoot>
<AvatarImage src="https://i.pravatar.cc/150?u=cosmic-ui" alt="User avatar" />
<AvatarFallback>CU</AvatarFallback>
</AvatarRoot>
npx @left4code/cosmic-ui-cli@latest add avatar
This writes the component and everything it imports, then installs the packages it needs. Run npx @left4code/cosmic-ui-cli@latest initfirst if you haven't already.
Install the following dependencies:
Built directly on the Zag.js state machine. The fallback and image both render unconditionally - the machine toggles a hidden attribute on whichever one shouldn't show, based on whether the image loaded. The square border shown here is a placeholder; swap it for the Frame primitive once its avatar-specific paths exist. Copy and paste the following code into your project.
import { createContext, useContext, useId } from "react";
import { twMerge } from "tailwind-merge";
import { useMachine, normalizeProps } from "@zag-js/react";
import * as avatarMachine from "@zag-js/avatar";
const AvatarContext = createContext<ReturnType<typeof avatarMachine.connect> | null>(
null
);
function useAvatarContext() {
const api = useContext(AvatarContext);
if (!api) throw new Error("Avatar parts must be used within <AvatarRoot>");
return api;
}
function AvatarRoot({
children,
className,
...rest
}: React.PropsWithChildren<Partial<avatarMachine.Props> & { className?: string }>) {
const service = useMachine(avatarMachine.machine, { id: useId(), ...rest });
const api = avatarMachine.connect(service, normalizeProps);
return (
<AvatarContext.Provider value={api}>
<span
{...api.getRootProps()}
className={twMerge([
"relative inline-flex size-10 items-center justify-center overflow-hidden border border-primary/30 bg-primary/10",
className,
])}
>
{children}
</span>
</AvatarContext.Provider>
);
}
function AvatarImage({
src,
alt,
className,
}: {
src: string;
alt: string;
className?: string;
}) {
const api = useAvatarContext();
return (
<img
{...api.getImageProps()}
src={src}
alt={alt}
className={twMerge(["size-full object-cover", className])}
/>
);
}
function AvatarFallback({
children,
className,
}: React.PropsWithChildren<{ className?: string }>) {
const api = useAvatarContext();
return (
<span
{...api.getFallbackProps()}
className={twMerge(["font-medium", className])}
>
{children}
</span>
);
}
export { AvatarRoot, AvatarImage, AvatarFallback };
Update the import paths to match your project setup.
import { AvatarRoot, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
<AvatarRoot>
<AvatarImage src="https://i.pravatar.cc/150?u=cosmic-ui" alt="User avatar" />
<AvatarFallback>CU</AvatarFallback>
</AvatarRoot>