Building a Custom Avatar Generator
I recently tried creating some fallback avatars for my users who haven't uploaded an avatar yet.
This guide walks you through how I created a custom avatar generator that produces unique, colorful avatars based on a user's name.
This utility offers a consistent and nicer alternative to the dreaded empty or broken image.
The Code
Let's start by examining the complete code for my avatar generator:
const colors = [ // Reds "#f87171", "#ef4444", "#dc2626", "#7f1d1d", // Oranges "#fb923c", "#ea580c", // Yellows "#fbbf24", "#d97706", // Greens "#84cc16", "#65a30d", "#4d7c0f", // Teals "#14b8a6", "#0d9488", "#134e4a", // Blues "#0ea5e9", "#0284c7", "#0369a1", "#0c4a6e", // Indigos "#6366f1", "#4338ca", "#3730a3", "#312e81", // Purples "#8b5cf6", "#7c3aed", "#4c1d95", // Pinks "#ec4899", "#db2777", "#831843", ]; function hashCode(str: string) { let hash = 0; for (let i = 0; i < str.length; i++) { const char = str.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash & hash; // Convert to 32-bit integer } return Math.abs(hash); } export const generateAvatar = (name: string) => { if (!name || typeof name !== "string") { throw new Error("Name must be a non-empty string"); } const firstLetter = name.charAt(0).toUpperCase(); const hash = hashCode(name); const colorIndex = hash % colors.length; const backgroundColor = colors[colorIndex]; const svg = ` <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"> <rect width="100" height="100" fill="${backgroundColor}" /> <text x="50" y="50" font-family="Arial, sans-serif" font-size="50" fill="white" text-anchor="middle" dy=".35em">${firstLetter}</text> </svg> `; const dataUri = `data:image/svg+xml;charset=UTF-8,${encodeURIComponent(svg)}`; return dataUri; };
Now, let's break down each part of the code and explain its purpose.
Color Palette
const colors = [ // Reds "#f87171", "#ef4444", "#dc2626", "#7f1d1d", // ... (other color groups) ];
We start by defining a color palette. This array contains a load of colors I liked, spanning various hues. A predefined palette ensures that our avatars have a good variety and will blend in with our designs.
Hash Function
function hashCode(str: string) { let hash = 0; for (let i = 0; i < str.length; i++) { const char = str.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash & hash; // Convert to 32-bit integer } return Math.abs(hash); }
This hashCode
function converts a string (in our case, a username) into a numeric value. It ensures that the same input always produces the same output, which is crucial for generating consistent avatars.
Avatar Generation Function
At the heart of our utility is the generateAvatar
function. This function takes a username as input and returns a data URI representing the generated avatar. Let's dive into how it works:
export const generateAvatar = (name: string) => { // Function body will be explained below };
Our function begins with input validation to ensure we're working with a valid username:
if (!name || typeof name !== "string") { throw new Error("Name must be a non-empty string"); }
This check guarantees that we have a non-empty string to work with, preventing potential errors down the line.
Next, we process the name to extract its first letter:
const firstLetter = name.charAt(0).toUpperCase();
This simple operation gives us the capitalized initial that will be displayed on our avatar.
To select a background color, we use our hashCode
function in combination with the color palette:
const hash = hashCode(name); const colorIndex = hash % colors.length; const backgroundColor = colors[colorIndex];
By using the hash of the name, we ensure that the same name always gets the same color, while the modulo operation gives us a nice distribution across our color palette.
With our color selected, we can now generate the SVG for our avatar:
const svg = ` <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"> <rect width="100" height="100" fill="${backgroundColor}" /> <text x="50" y="50" font-family="Arial, sans-serif" font-size="50" fill="white" text-anchor="middle" dy=".35em">${firstLetter}</text> </svg> `;
This SVG creates a 100x100 square with our selected background color and places the capitalized first letter of the name in the center, styled in white.
Finally, we convert our SVG to a data URI, making it ready to use as an image source:
const dataUri = `data:image/svg+xml;charset=UTF-8,${encodeURIComponent(svg)}`; return dataUri;
By encoding our SVG and prefixing it with the appropriate data URI scheme, we create a string that can be directly used as the src
attribute of an <img>
tag.
And that's it! Our generateAvatar
function takes a name, processes it, and returns a unique, colorful avatar as a data URI. This approach is efficient, consistent, and requires no external resources or API calls.
If you have any suggestions on how to improve it let me know in the comments.