IAN WALDRON IAN WALDRON

Default Avatars With User Initials

Simple default avatars displaying the logged-in user's initials for use as a fallback when a profile picture isn't set.
June 23, 2024
  • Fallback for user avatar
  • Circle with center-aligned content both vertically and horizontally using flex; and
  • Inject user initials using content attribute of pseudo element :before

Background

For my projects that have restricted features, especially projects that involve displaying data, I generally have user profiles that accept a user-supplied profile picture. Usually this is used to display the logged-in user in the header or to indicate in data tables which user is associated with certain records, actions, privileges, etc. However, I generally don't structure user profile models with profile pictures as a required field. Therefore, I need a fallback option for when the profile picture hasn't been set that still conveys useful information and looks nice.

HTML

<div class="avatar-container">
  <button class="avatar" type="button">
    <span data-letters="AB"></span>
  </button>
  <button class="avatar">
    <span data-letters="AB"></span>
  </button>
  <button class="avatar">
    <span data-letters="AB"></span>
  </button>
  <button class="avatar">
    <span data-letters="AB"></span>
  </button>
</div>

GitHub

Here we have a handful of button elements with the class "avatar", a child span element with a data-<label> attribute, and a value for the data attribute representing our example user's initials. Ignore the container and the multiple avatars. I added a couple variations to demonstrate different gradients and positioned them in a flexbox container to organize them neatly. In production, you'll have a single avatar per user and it will be nested in a nav or perhaps a table.

For my purposes, I'm starting with button elements for my avatars because my most common use case is a nav button that displays a dropdown with options like, "profile," "log out," and so on. If I was only using an avatar to indicate possession or relation to a record or action, such as with a data table, I would use a div instead of a button. I just need an element that respects "width" and "height" properties since the circle's size is fixed.

With the attribute "data-letters," we're storing the user's initials to be later injected as content with css. The syntax for this is "data-<lable>." I'm choosing the "letters" part. You can call it "initials," "foo," "bar," or whatever you'd like.

CSS 

.avatar {
  /* button */
  border: none;
  font-family: inherit;
  cursor: pointer;
  outline: inherit;
  
  height: 4rem;
  width: 4rem;
  border-radius: 50%;
  color: #fff;
  
  /* center the data within */
  display: flex;
  align-items: center;
  justify-content: center;
}

/* initials */
.avatar > span[data-letters]::before {
  content: attr(data-letters);
  font-size: 1.3rem;
}

/* background gradients */

.avatar:nth-child(1) {
  background: linear-gradient(to right top, #4B31A1, #B32993)
}

.avatar:nth-child(2) {
  background: linear-gradient(to right top, #970008, #FF6F91)
}

.avatar:nth-child(3) {
  background: linear-gradient(to right top, #008B72, #54FBDD);
}

.avatar:nth-child(4) {
  background-image: linear-gradient(to right top, #2E3192, #1BFFFF)
}

/* display for this pen */

html {
  font-family: sans-serif;
}

.avatar-container {
  display: flex;
  flex-wrap: wrap;
  gap: 25px;
  margin-bottom: 1rem;
}

.avatar-container > * {
  flex: 0 0 auto;
}

GitHub

The CSS to accomplish this is relatively simple. First, I adjust a couple of properties to prevent default button styles from interfering. Next, I'm styling my ".avatar" element with fixed width and height properties as well as a "border-radius" property of 50% to accomplish the circle shape. Then, I establish by avatar as a flexbox with vertical and horizontal center alignment to position the content in the center of the shape.

To capture the initials and then inject them into view, I use the "content" property of the pseudo element ::before. In CSS, there exists a function attr() that retrieves an attribute's value. I use this function to grab the initials and then pass them to the "content" property.

Last, I add a background gradient to make the shape a little more visually interesting. I'm using the nth-child selector to apply the different gradients in this example. In practice, I would assign each gradient to its own class and conditionally inject the class dependent on a stored user preference. That way, you allow a user to choose their own default avatar.

When setting the initials to the content property, the selector "span[data-letters]::before" can be used without "[data-letters]." For example ".avatar > span::before" would also work. The "[data-letters]" component adds an additional layer of specificity to the selector where direct child spans to parent with class "avatar" will only be selected if the span contains the "data-letters" attribute.

Result

See the Pen default-avatars by Ian Waldron (@Ian-Waldron) on CodePen.

Final Thoughts

The above is a simple and easy way to give users a default option for a user avatar. Please note, the shapes are much larger than I would actually use in production. I sized them up to 4rem for presentation purposes. Something around 2rem to start and expand with screen size would be more appropriate. Enjoy.

Here's the GitHub and Codepen for the project.