Sleeper

Sleeper

Sleeper

Trash talk, organized.

Trash talk, organized.

Trash talk, organized.

Overview

Overview

The Problem

Sleeper is trusted by 13+ million players, and a league lives in its chat: trash talk, trade talk, draft-day plans. On web, chat was a single pane with a plus, a GIF button and an emoji button. There were no DMs, no way to catch a mention from another league, nothing to keep an important message from scrolling away, and it sat on a draft screen that was already full.

My Role

Product Design Intern at Sleeper (Blitz Studios), June to August 2026.

I worked inside the design team’s 2027 design system, alongside two other interns. I was given the web chat to translate into the new design system, and I expanded it into a full system. The chat modal and reply shipped.

Tools: Figma.

Tech Stack

Figma

Design Tool

Tech Stack

Figma

Design Tool

Type

Product Design Internship

Created

2026

Process

Process

The old chat was a single-state pane with a plus, a GIF button and an emoji button. I expanded it into a full system.

The old Sleeper web chat: the default pane, the emoji picker and the GIF picker

Collapsed first

A collapsed bar with an unread count and a stack of member avatars. It starts collapsed because the draft screen already carries a board, a player table and a side panel, and chat shouldn’t compete with them until you open it. Collapsed or open, it’s the same title bar: a drag handle, the unread count, who’s here, and buttons for pinned messages, DMs and collapse. Pinned messages, DMs and mentions open in place of the feed, with a back arrow to return.

The chat title bar zoomed in and labeled: drag handle, unread count, who's here with a +8 overflow, pinned, DMs and collapse; beside it, the collapsed bar in light and dark and the chat it opens into

DMs and group DMs

A DM list with search, one-on-one conversations, and group conversations, so trade talk and side conversations don’t have to happen in the league thread.

The DM list with search in light, a one-on-one conversation in dark and a group DM in light

A mentions inbox across leagues

If you’re in more than one league, mentions from all of them land in one place, each row naming its league, with Mark all as read.

The mentions inbox in light and dark, with one row zoomed in: the unread dot, the league it came from, your @mention and when

Pinned messages

An empty state and a populated view, with the pinned message set apart, so league rules and draft-day details don’t scroll away.

Pinned messages: the empty state and the populated view in light, and the populated view in dark

One message, every kind of message

Every message is one component: a header with avatar, name and time, the body, and a row of reactions. Your own reactions show in aqua, and the add button opens an emoji picker built into the message. Between the body and the reactions sits a slot, so GIFs, images and polls drop into the same component instead of needing their own. More options holds Copy and Reply, and the attach menu adds a poll.

One chat message zoomed in (dark) and labeled: header, message body, reactions with your own highlighted, the add-reaction button and the Copy and Reply menu; beside it, the same message component in a light group DM

Input states

Default, selected, reply, attachment, reply with attachment, and @-suggestions, each in light and dark. Every row below is the same input component with different properties switched on, so each state shows at a glance what you’re replying to, what’s attached, and whether there’s anything to send. Send follows one rule in all of them: disabled until there’s text or an attachment. I designed that disabled state in both themes.

State matrix of the chat input: six states in rows, showing which of the reply, attachment and @-suggestions properties is on, what's in the field, whether Send is disabled or enabled, and the state in light and dark

Built as components

I built the chat as components, not screens. The chat component nests a title bar, a feed and an input. The feed holds a slot for messages, and each message has its own slot for rich content. The input is one component with four properties: theme, reply, graphic attachment and @-suggestions. Every input state on this page is that component with different settings, not a redrawn frame. The components are mine. The tokens, type styles, buttons and avatars they’re built on come from the design team.

The chat broken into its title, feed and input components, next to the chat input's four properties and one instance set to dark, reply and @-suggestions

Working inside the token system

The design team had already defined the color tokens: 1,499 matched color properties across light and dark, 89 dark-only and 37 light-only. My job was to apply them, not define them. I followed the team’s gray mappings between themes, for example Gray/400 to Gray/300 and Gray/700 to Gray/25, so every chat and auction frame has a matching light and dark state. The ramp is the design team’s. Below, each role in the chat gets one light and one dark token, and each pair is checked for contrast.

The same chat in light and dark, next to the design team's gray ramp and the token each role uses: content Gray/0 and Gray/900, title and input bars Gray/5 and Gray/800, menus and buttons Gray/0 and Gray/700, primary text Navy and Gray/0, secondary text Gray/500 and Gray/200, tertiary text Gray/400 and Gray/300, borders Gray/100 and Gray/600

Conclusion

Conclusion

What Happened Next

The chat modal and reply shipped. DMs, the mentions inbox, pinned messages, reactions and attachments were designed and handed off.

What I’d Do Differently

Set up light and dark as roles from the first frame. I matched tokens frame by frame, which let small drift creep in: a layer detached here, a hex value typed in there. Starting from roles would have made consistency the default instead of something to check for.

Next Project

Next Project

Next Project

WheareAI

WheareAI

WheareAI

->

->

->

Ed Roa © 2026

Ed Roa © 2026

Ed Roa © 2026