React
An avatar is a pure function of its seed, so in React it's a small component with no state and no effects. It renders the same on the server and the client.
An avatar component
import { useMemo } from 'react';
import { botlingDataUri } from 'seedkin/botling';
export function Avatar({ id, size = 40 }: { id: string; size?: number }) {
const src = useMemo(() => botlingDataUri(id, { size, title: null }), [id, size]);
return <img src={src} alt="" width={size} height={size} />;
}
title: null leaves the accessible name to the <img>. Keep alt="" when the person's name sits next to the avatar, so screen readers don't say it twice; otherwise describe it, such as alt={`${user.name}'s avatar`}.
It has no hooks that need the browser, so it works as a Server Component in Next.js without 'use client'. There, the useMemo can go.
Inline SVG
import { botling } from 'seedkin/botling';
export function InlineAvatar({ id, size = 40 }: { id: string; size?: number }) {
return <span dangerouslySetInnerHTML={{ __html: botling(id, { size, title: null }) }} />;
}
Inlining is safe: the seed never appears in the markup, and a title you pass is escaped. Prefer the <img> for long lists, since the browser decodes each image once and keeps the DOM small, and for animated avatars on pages with a strict Content Security Policy (see Animation).
Other styles
Swap the import for another style; the options are the same:
import { snootDataUri } from 'seedkin/snoot';
<img src={snootDataUri(user.id, { size: 40, title: null })} alt="" width={40} height={40} />