Skip to content

Exercises

Supporting screen readers

We've used JavaScript operators to conditionally render a green circle next to online users' names, but there's a problem: what happens when someone visits our application using a screen reader?

Let's consider the following DOM structure:

<ul class="friends-list">
<li class="friend">
Andrew
</li>
<li class="friend">
<div class="green-dot"></div>
Beatrice
</li>
<li class="friend">
<div class="green-dot"></div>
Chen
</li>
</ul>

The trouble is that the <div class="green-dot"> is semantically meaningless, and so screen readers will ignore it. If someone can't see the screen, they'll have no idea that this random div is meant to signify that someone is online!

How can we make this information available to folks who use a screen reader? Well, there are a number of valid approaches, but my personal favourite is to use some CSS to visually hide a chunk of text.

Here's what this looks like, using a custom VisuallyHidden component:

<p>
This text is shown normally.
<VisuallyHidden>
This text isn't on the screen, but is announced by screen readers.
</VisuallyHidden>
</p>

Your task is to use this component to add the suffix “(Online)” after the names of online users.

Acceptance Criteria:

  • Users who are online should have the text “(Online)” added after their names.
  • The VisuallyHidden component should be used to make sure that this text isn't shown visually.
  • Users who are offline should not be affected.

Code Playground

import VisuallyHidden from './VisuallyHidden';

function Friend({ name, isOnline }) {
return (
<li className="friend">
{isOnline && <div className="green-dot" />}
{name}
</li>
);
}

function App() {
return (
<ul className="friend-list">
<Friend name="Andrew" isOnline={false} />
<Friend name="Beatrice" isOnline={true} />
<Friend name="Chen" isOnline={true} />
</ul>
)
}

export default App;

Solution:

If you'd like to learn more about this component, and see a “souped up” version with the ability to toggle visibility in development mode, check out the VisuallyHidden snippet on my blog.

User Profile with Badges

Certain community sites, like LinkedIn or StackOverflow, have "badges", small awards for people who achieve certain goals or who fit certain requirements.

In this exercise, we're going to update a set of user profiles to conditionally render some badges.

Here's what this should look like, for folks who have at least 1 badge:

A user profile showing 3 badges in a dashed-border box

For users who have no badges, though, this whole section should be omitted. Things should stay as they are:

A user profile with no badges, and no border box

The markup for badges looks like this:

<ul class="badge-list">
<li>Badge 1</li>
<li>Badge 2</li>
<li>Badge 3</li>
</ul>

Acceptance Criteria:

  • If the user has at least 1 badge, an unordered list with the class badge-list should be rendered, using the data from profile.badges.
  • Each badge should be its own list item, with badge.label being rendered within.
  • There should be no “key” warnings in the browser console. You can trust that the badge slugs are unique.

Stretch goal:

If the user has 3 or more badges, a golden color should be applied:

A user profile showing 3 badges in a dashed-border box

This can be done by adding the golden class to the <ul>:

<ul class="golden badge-list">
<li>Badge 1</li>
<li>Badge 2</li>
<li>Badge 3</li>
</ul>

Code Playground

// GOAL:
// Render an unordered list with the class
// “badge-list” when the user has at least
// 1 badge.
//
// Each badge is an object with this shape:
// { slug: string, label: string }
//
// STRETCH:
// If the user has 3+ badges, the “golden”
// class should be added to the unordered
// list (in addition to “badge-list”).

function ProfileCard({ profile }) {
return (
<article className="profile-card">
<header>
<img
alt={profile.imageAlt}
src={profile.imageSrc}
/>

<h2>{profile.name}</h2>
<p className="joined">
Joined {profile.joinDate}
</p>
</header>
</article>
);
}

export default ProfileCard;

Solution: