Docs

Add avatars in three steps

Pick your framework, install one package and render. Everything else on this page is optional.

Quick start

  1. Install

    npm i @inlaylab/opaline @inlaylab/opaline-react
  2. Import a style

    Styles are separate imports, so you ship only the ones you use. Swap clay for morph, gradient, aura or initials.

    import { Avatar } from '@inlaylab/opaline-react'
    import { clay } from '@inlaylab/opaline/clay'
  3. Render it

    Pass anything stable as the seed: a user ID, email or name.

    export function UserAvatar({ user }) {
      return <Avatar seed={user.email} look={clay} size={48} />
    }

    Works in Server Components. Without a photo it ships no client code at all.

Styles

Five looks, one API. Each is its own import path: @inlaylab/opaline/<style>.

ClayLittle characters: a jelly body, or a hood with cat, bear or bunny ears.@inlaylab/opaline/clay
MorphAn organic blob with a face.@inlaylab/opaline/morph
GradientSmooth shapes with expressive faces.@inlaylab/opaline/gradient
AuraA glowing orb of blended color.@inlaylab/opaline/aura
InitialsReadable letters on a seeded tile.@inlaylab/opaline/initials

Options

Set an option to fix that part; the seed fills in the rest. An option set to its default gives exactly the same avatar as leaving it out.

OptionValuesWhat it does
seedstring · number · nullAny string: user ID, email, name. Emails are lower-cased; whitespace is trimmed.
sizenumberPixel size. Default 64 (40 in groups).
palettevivid · pastel · electric · muted · warm · cool · monoColor family. Default vivid.
shapecircle · squircle · squareEvery style. Aura and Initials default to circle; on the others it adds a tinted tile.
finishflat · soft · glossLight and shade. Morph and Gradient default to flat, Clay to soft.
expressionbeam · content · … · giggleFix the face. Or set mood: happy · calm · surprised · playful.
facebooleanMorph, Gradient and Clay show a face unless false.
familyegg · duo · tri · cushion · clover · petalMorph and Gradient blob shape.
body · earsjelly · hood · cat · bear · bunnyClay only. Ears go with the hood.
textstringInitials only. Up to 3 letters, shown as given.
backdropnone · tintA soft circle behind the body.
src · altstringComponents only: a photo shown once it loads, and an accessible name.
members · maxarray · numberGroups only: who to show, and how many before the +N chip.

Photos and names

Pass src and the photo appears once it loads. If it fails, the generated avatar stays, so nobody sees a broken image. Pass alt to give the avatar an accessible name; without it, the avatar is decorative and hidden from screen readers.

<Avatar seed={user.email} look={clay} src={user.photoUrl} alt={user.name} />

Initials and shapes

initials takes the letters from the seed (ada.lovelace@inlay.dev gives AL) or from text. The letters are a deep shade of the tile's color and clear WCAG AA contrast on every palette. Every style takes shape.

circle
squircle
square
pastel
warm
cool
text="Op"

Avatar groups

Overlapping avatars with a +N chip for everyone past max. Set --avatar-ring to your background color; --avatar-more-bg and --avatar-more-fg color the chip.

import { AvatarGroup } from '@inlaylab/opaline-react'

<AvatarGroup
  look={clay}
  members={team.map((u) => ({ seed: u.email, src: u.photoUrl, alt: u.name }))}
  max={4}
  alt="Project members"
/>

PNG export

For places that take no SVG: profile photo uploads, social cards, push notifications. toPng renders in the browser with no dependencies. On the server, forRaster bakes the colors in for a rasterizer such as resvg. Pass vars to bake in theme colors.

Browser
import { toPng } from '@inlaylab/opaline/png'

const png = await toPng(createAvatar(clay, { seed }), { size: 512 })
// a Blob: upload it, or URL.createObjectURL(png) to show or download it
Server
import { forRaster } from '@inlaylab/opaline/png'
import { Resvg } from '@resvg/resvg-js'

const svg = forRaster(createAvatar(clay, { seed }), { size: 512 })
const png = new Resvg(svg).render().asPng() // a Buffer

Theming

Colors come out as var(--avatar-c1, #hex). Set the variables on any parent to follow your brand or dark mode, with no re-render. --avatar-c1 is always the body; --avatar-fg colors initials.

Server rendering

Server and browser produce the same markup, so hydration never warns. Gradient IDs are scoped per seed and options, and each component instance adds its own suffix, so two avatars on one page never clash. The repo has tested samples for Next (App Router), Nuxt, SvelteKit and Angular SSR.

Same seed, same avatar

The seed is normalized (trimmed, NFC, emails lower-cased) and hashed into a seeded generator: no Math.random, no dates. The same seed and options give a byte-identical SVG across 1.x, checked by checksums in CI, so you can cache avatars on a CDN or store them.

Not sure Opaline is the right fit? See how it compares with DiceBear and Boring Avatars →