AIOStreamsAIOStreams
Reference

Web app themes and custom CSS

Change the web app's colours, restyle it with your own CSS, and the selectors to style its parts by.

The web app's Theme settings, under Settings → Theme, change its look for you on every device you sign in on. Each user of a server has their own.

  • Presets set an accent and a background colour together.
  • Accent colours buttons, progress bars and highlights.
  • Background colours pages and panels, which take their shades from it. Dark colours read best.
  • Custom CSS goes on top of the theme, for anything the colours don't cover.

Adding custom CSS

Write your CSS in the Custom CSS box and press Apply CSS. A message then asks whether to keep it: press Keep, or it is undone after 15 seconds. That way CSS that hides the page, or the button, can't lock you out. Your text stays in the box either way, so you can fix it and try again.

Once kept, it is saved to your account and applies on every device you sign in on. It doesn't apply on the sign-in screens, since nobody is signed in there yet.

If your CSS ever breaks the app on some device, add ?safe to the address (for example https://example.com/web/?safe). Custom CSS stays off for that visit, so you can fix or clear it in the settings.

A server's own CSS

A server's owner can style the app for everyone signed in to it, with App custom CSS in the dashboard's Branding settings, or APP_CUSTOM_CSS. It applies on the sign-in screens too, and before everyone's own custom CSS, so yours still wins. To leave it out for yourself, turn off Use this server's CSS under Settings → Theme. ?safe turns it off for that visit as well.

Finding what to style

Parts of the app carry a data-ui attribute naming what they are, and other data-* attributes saying which one or what state it's in. Aim your CSS at these rather than at class names, which change between versions.

To find a part's name, right-click it in a browser and choose Inspect, then look at the data-ui on it or on the elements around it. The reference below lists them all.

/* Every progress bar */
[data-ui='progress-bar-fill'] {
  background: hotpink;
}

/* Only those in the continue watching row */
[data-row='resume'] [data-ui='progress-bar-fill'] {
  background: hotpink;
}

Examples

True black

The Background setting does this best, since panels take their shades from it. With CSS:

:root {
  --background: #000;
  --paper: #000;
  --color-gray-950: 0 0 0;
  --color-gray-900: 10 10 10;
}

Squarer corners

[data-ui='poster-card-image'],
[data-ui='wide-card-image'],
[data-ui='episode-image'] {
  border-radius: 0.25rem;
}

Dim what you've watched

:is([data-ui='poster-card'], [data-ui='wide-card'])[data-watched]
  [data-ui='artwork'] {
  opacity: 0.4;
}

No zoom on hover

[data-ui='poster-card']:is(:hover, :focus-visible) [data-ui='artwork'],
[data-ui='wide-card']:hover [data-ui='artwork'],
[data-ui='wide-card'] :focus-visible [data-ui='artwork'] {
  transform: none;
}

Bigger posters in rows

[data-ui='media-row'][data-shape='poster'] [data-ui='media-row-item'] {
  flex-basis: 14rem;
}

Hide a row on the home page

[data-row='upcoming'] {
  display: none;
}

A catalog's row is named view: and then its id. To find the id, open the catalog by clicking the row's title: the id is the part of the address after /discover/.

[data-row='view:abc123'] {
  display: none;
}

To hide the featured banner, set Featured on home to Nothing under Settings → Interface instead.

Hide what a catalog holds

A catalog's row on the home page says what it holds, such as Shows or Movies, beside its title.

[data-ui='media-row'][data-row^='view:'] [data-ui='media-row-title'] a > span {
  display: none;
}

Mark your favourites

[data-ui='poster-card'][data-favourite] [data-ui='poster-card-image']::after {
  content: '♥';
  position: absolute;
  top: 0.5rem;
  left: 0.5rem;
  z-index: 2;
  color: #f43f5e;
  font-size: 1.25rem;
  text-shadow: 0 1px 4px rgb(0 0 0 / 0.6);
}

Hide spoilers

This needs no CSS: turn on Blur episodes you haven't started under Settings → Interface → Spoilers. It covers title pages, the player's episode list and the continue watching, next up and upcoming rows.

Hide buttons on title pages

[data-ui='item-action']:is([data-name='trailer'], [data-name='drop']) {
  display: none;
}

More buttons beside Play on a phone

On a phone, a title's page shows three actions beside More, which lists every action. They are the first three the title offers of trailer, watched, favourite, download, rating, add-to-playlist, random, party, play-on and drop, and carry data-shown. To bring another one out, name it:

[data-ui='item-quick-action'][data-name='party'] {
  display: flex;
}
[data-ui='item-more-action'][data-name='party'] {
  display: none;
}

Pages in the bottom bar

The bar shows Home, Discover, Search and Favourites and lists the other pages under You. Every page is in both, with data-shown on the ones the bar shows. To swap Favourites for Live TV:

[data-ui='mobile-nav-item'][data-name='live'] {
  display: flex;
}
[data-ui='mobile-nav-item'][data-name='favourites'],
[data-ui='account-menu-page'][data-name='live'] {
  display: none;
}
[data-ui='account-menu-page'][data-name='favourites'] {
  display: flex;
}

The pages are home, discover, search, favourites, live, calendar, activity, playlists, party and downloads. Live TV shows only on a server with live channels.

Smaller icons in the bottom bar

Without names, the bar's icons are a little bigger. For the smaller ones, spaced further apart:

[data-ui='mobile-nav'][data-names='hidden'] [data-ui='mobile-nav-item'] {
  width: 3.5rem;
  padding-block: 0.875rem;
}
[data-ui='mobile-nav'][data-names='hidden'] [data-ui='mobile-nav-item'] svg {
  font-size: 1.25rem;
}

No parallax

A title's backdrop and the rotating hero scroll away at half the page's speed. To keep them with the page:

:is([data-ui='item-backdrop'], [data-ui='hero-backdrops']) {
  animation: none;
}

Hide the score, and the dot before it

[data-ui='item-meta'] [data-name='score'],
[data-ui='meta-separator']:has(+ [data-name='score']) {
  display: none;
}

Episodes without their air dates

[data-ui='episode-meta'] [data-name='aired'],
[data-ui='episode-meta'] [data-name='aired'] + [data-ui='meta-separator'] {
  display: none;
}

Seasons without the bar

Mark the open season by its brighter poster and bolder name alone:

[data-ui='season-indicator'] {
  display: none;
}
[data-ui='season-poster'][data-selected] [data-ui='season-name'] {
  font-weight: 600;
}

Only some ratings

Keep IMDb and the Rotten Tomatoes critics' score, wherever a title's ratings show:

[data-ui='score']:not([data-source='imdb'], [data-source='tomatoes']) {
  display: none;
}

Square cast photos

[data-ui='person-card-image'] {
  border-radius: 0.75rem;
}

Versions

/* Mark cached versions */
[data-ui='version'][data-cached] {
  border-color: rgb(var(--color-brand-500) / 0.6);
  background: rgb(var(--color-brand-500) / 0.08);
}

/* Ring the top version, since the list is sorted best first */
[data-ui='version']:nth-child(1 of [data-ui='version']) {
  box-shadow: 0 0 0 1px rgb(var(--color-brand-400));
}

/* Names in a fixed-width font, for formats laid out in columns */
[data-ui='version-name'],
[data-ui='version-description'] {
  font-family: ui-monospace, monospace;
}

/* A wider list on big screens */
[data-ui='dialog'][data-name='versions'] {
  max-width: 72rem;
}

/* Hide quick filters that find nothing for this title */
[data-ui='versions-quick-filter'][data-empty] {
  display: none;
}

/* Bigger badges */
[data-ui='version-badge'] {
  height: 1.75rem;
  font-size: 0.8125rem;
}

Leave choosing which versions appear to your filters, rather than hiding some with CSS. Hidden versions still count, and playing straight away or carrying on to the next episode can still pick them.

The player

/* A red timeline, thicker on hover */
[data-ui='seek-bar-progress'] {
  background: #e50914;
}
[data-ui='seek-bar-track'] {
  height: 6px;
}
[data-ui='seek-bar']:hover [data-ui='seek-bar-track'] {
  height: 10px;
}

/* Drop buttons you never use */
[data-ui='player-button']:is([data-name='speed'], [data-name='fit']) {
  display: none;
}

/* Bigger track lists, with the chosen one in the accent colour */
[data-ui='player-menu-item'] {
  font-size: 1.1rem;
}
[data-ui='player-menu-item'][data-selected] {
  color: rgb(var(--color-brand-300));
}

To change how subtitles look in a browser, style video::cue. The desktop and Android apps draw subtitles themselves, so use Settings → Subtitles there.

video::cue {
  font-family: 'Trebuchet MS', sans-serif;
}

Your own font

@import has to come first in the box.

@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@400;600;700&display=swap');

body {
  font-family: 'Outfit', sans-serif;
}
[data-ui='brand-logo'] {
  content: url('https://example.com/logo.png');
}

Hide the scrollbar

html {
  scrollbar-width: none;
}
::-webkit-scrollbar {
  display: none;
}

Messages in the bottom right

On a phone they stay at the top, where they span the screen.

@media (min-width: 640px) {
  [data-sonner-toaster] {
    top: auto !important;
    bottom: 24px !important;
    left: auto !important;
    right: 24px !important;
    transform: none !important;
  }

  /* Each message sits at the bottom, with older ones stacked above */
  [data-sonner-toast] {
    top: auto !important;
    bottom: 0 !important;
    --lift: -1 !important;
    --lift-amount: calc(-1 * var(--gap)) !important;
  }
}

No fade-ins

[data-page],
[data-ui='media-row-item'] > div,
[data-ui='card-grid'] > div,
[data-ui='episode-list'] > div > div {
  opacity: 1 !important;
  transform: none !important;
  top: 0 !important;
}

Window buttons in a pill of their own

With the navigation along the top, the desktop app puts its window buttons at the end of the last pill. To give them a pill of their own:

[data-ui='top-tabs'][data-style='pill'] [data-ui='top-tabs-end'] {
  gap: 1.5rem;
  padding: 0;
  border: none;
  background: none;
  box-shadow: none;
  backdrop-filter: none !important;
}
[data-ui='top-tabs'][data-style='pill'] [data-ui='top-tabs-divider'] {
  display: none;
}
[data-ui='top-tabs'][data-style='pill']
  :is([data-ui='top-tabs-actions'], [data-ui='top-window-buttons']) {
  padding: 0.375rem;
  border: 1px solid rgb(255 255 255 / 0.1);
  border-radius: 9999px;
  background-color: rgb(14 14 18 / 0.55);
  backdrop-filter: blur(24px) saturate(1.8);
  box-shadow: 0 12px 32px -12px rgb(0 0 0 / 0.7);
}

Only in one app

/* A bigger timeline in the desktop app only */
html[data-host='desktop'] [data-ui='seek-bar-track'] {
  height: 8px;
}

/* No suggestions under the search box in the Android app on a TV */
html[data-host='android-app'][data-tv] [data-ui='search-suggestions'] {
  display: none;
}

When a rule doesn't take

Your CSS comes after the app's own, so a rule as specific as the app's wins. When one doesn't:

  • Hover and focus styles need the same state in your selector. The zoom on a hovered poster, for example, is only undone by [data-ui='poster-card']:hover [data-ui='artwork'].
  • Animations set their styles on the element itself, which only !important beats. Fade-ins and the message popups are like this.
  • Class names change between versions, so a rule aimed at one can stop working after an update. The data-ui names and the shared component classes are kept stable.

What CSS can't change

  • Subtitles in the desktop and Android apps, which the player draws. Use Settings → Subtitles.
  • The page while a video plays in the desktop app. It has to stay see-through for the video beneath it, so custom CSS can't give it a background then.
  • The mini player's video in the desktop and Android apps, which the app draws itself where the page places the card. Moving or resizing mini-player with CSS leaves the video where it was.
  • The sign-in screens, before anyone is signed in.

Selectors

States are attributes set only while true, such as data-watched. Match them with [data-watched], or :not([data-watched]) for the opposite.

The whole page

SelectorWhat it is
html[data-host]Which app you're in: browser, desktop (AIOStreams' desktop app), android-app (AIOStreams' Android app), webos or tizen (the TV apps), jellyfin-desktop, android or jellyfin-app (another Jellyfin app that loads the web client)
html[data-platform]In the desktop app, the system: windows, linux or macos
html[data-tv]Set on a TV: in the LG and Samsung apps, and in the Android app on Android TV
html[data-nav]The navigation on a wide screen: sidebar, on a touch screen rail or bar, and on a TV tv-rail or tv-top. A narrow screen always has the bar at the bottom
html[data-in-rows]Set while focus is in the rows under a banner that follows the selected card
html[data-pointer-focus]Set while focus came from a mouse or a touch, not from keys, a remote or a gamepad
html.playingSet while the player fills the window, not in the mini player
html[data-blur-spoilers]Set while Blur episodes you haven't started is on
[data-page]Each page's container: home, discover, library (a catalog), search, favourites, live, calendar, history, downloads, settings, item, person, player or sign-in. A trailer's player is player with data-name="trailer"
[data-page='sign-in']The screens before you're signed in; data-name is sign-in, quick-connect, user-picker, servers or unreachable
page-backgroundThe colour behind every page
shellThe pages and the navigation, kept under the player while a video plays
page-body, page-header, page-titleA page's padded column, its heading row and its title
page-messageA message that fills the page, such as when there are no catalogs. The message itself is [data-luffy-error] (see shared components)
section, section-titleA titled part of a page; data-name is episodes, collection, details or filmography
sidebarThe sidebar. Its items are .UI-VerticalMenu__item, with data-name (home, discover, search, favourites, live, calendar, activity, downloads, party, settings, account) and data-current="true" on the page you're on
sidebar-logo, brand-logoThe logo in the sidebar, and the logo itself (also on the sign-in screens)
sidebar-historyThe back and forward buttons in the sidebar, where the browser has none; data-name is back or forward
mobile-nav, mobile-nav-itemThe bar at the bottom on a phone, and on a touch screen set to it; data-names is shown or hidden. Every page is an item, with data-name as in the sidebar, data-shown on those the bar shows and aria-current on the page you're on
touch-rail, rail-itemThe rail down the side on a touch screen, and its items; data-shape="floating" when it floats over the page
tv-railA TV's navigation down the side; data-shape="floating" when it floats over the page
top-tabs, top-historyThe navigation along the top, on a TV or a wide window set to it; data-style is pill, bar or fade. top-history holds its back and forward buttons, where no browser has them
top-tabs-end, top-tabs-actions, top-tabs-divider, top-window-buttonsIts group at the end (the end pill in the pill style); the buttons in it; and, in the desktop app, the line and the window buttons after them
corner-menuThe navigation shrunk to a button in the top corner; data-open while it's open
nav-itemAn item in tv-rail, top-tabs and corner-menu; data-name as in the sidebar, and aria-current on the page you're on
download-ringThe ring around your picture while downloads run
account-menuThe menu under your picture; its items have data-name: settings, switch-user, configure, change-server, sign-out. From the bottom bar it also lists every page as account-menu-page, data-shown on those the bar shows
connection-note, connection-note-downloads, connection-note-dismissThe note while the server can't be reached, its Downloads button and its close button; data-state="small" once it's shrunk to an icon
update-toastThe message that an app update is ready. On a TV it's a dialog instead
window-controlsThe window buttons in the desktop app; each has data-name: minimise, maximise, fullscreen or close, and data-fullscreen is set while the window is full screen
pill-tabs, pill-tabA row of choices such as Movies / Shows; data-name says which row, data-selected marks the choice
dialogA dialog box; data-name is versions, overview, all-episodes, episodes and chapters (the player's), calendar-day, unaired (asking before playing or downloading an episode that hasn't aired), sync-to-line, external-player, trailers, update, party, send-report, crash-report, or quick-filters and badges (their settings editors)
avatarA user's picture or initial

Rows, grids and cards

SelectorWhat it is
home-rowsEverything under the featured banner on the home page
media-rowA scrolling row. data-row names it: resume, next-up, upcoming, now-playing, similar, cast, crew, seasons, episodes:<season id>, sub-collections, search:movies, search:shows, search:people, or view:<id> for a catalog. data-shape is poster, wide or square
media-row-title, media-row-action, media-row-nav, media-row-itemA row's title, the button beside it (such as Activity), its arrows, and each card's slot
card-gridA grid of cards; data-shape is poster or wide, data-size the poster size setting (small, medium, large)
poster-card, poster-card-image, poster-card-shade, poster-card-animated, poster-card-text, poster-card-title, poster-card-subtitleA poster, its picture, the shade over it on hover, the moving poster played while it's selected, and the lines under it. data-shape is poster, landscape or square, and data-type says what it is, such as Movie, Series or BoxSet. States: data-watched, data-favourite, data-in-progress
wide-card, wide-card-image, wide-card-play, wide-card-badge, wide-card-text, wide-card-title, wide-card-subtitle, wide-card-metaA landscape card, as in continue watching, with its play icon and corner badge. States: data-watched, data-in-progress, data-highlighted, data-dimmed, data-unavailable
artwork, artwork-fallbackA card's picture, and the title shown when it has none
progress-bar, progress-bar-fillHow far through something you are
watched-badge, unwatched-countThe tick on something watched, and the count of episodes left on a show
focus-ring, opened-pulseThe ring on a card the keyboard, a remote or a gamepad is on, and the brief one on the episode a page opened on
item-menuThe menu a card opens on right-click or a long press; its items have data-name: play, play-now, choose-version, details, open, watched, watched-up-to, remove-resume, favourite, download, downloads
card-previewThe bigger preview a card on the home page grows into while the pointer or focus rests on it; data-type says what it is. Hide it with display: none, or turn it off under Settings → Interface → Cards
card-preview-logo, card-preview-title, card-preview-episode, card-preview-genres, card-preview-overviewIts logo or title, the episode, the genres and the description
scoreOne rating in a line of facts, on title pages, the featured banner and card previews. data-source is imdb, tomatoes, tomatoesAudience, metacritic, letterboxd, rogerebert, trakt, tmdb, mal, or community for the server's own rating
card-preview-metaIts line of facts; each has data-name (year, or aired for an episode, score, length, rating), with a meta-separator between
open-card, open-card-posterA card opened in its row in place of a preview, and the poster fading off its start as it opens. Its slide (media-row-item) has data-open, data-opening while it opens and data-trailer while a trailer plays in it
trailer-preview-video, trailer-preview-embedA trailer playing by itself in a card, the banner or a title page, where the device has no player of its own beneath the page
SelectorWhat it is
heroThe banner; data-follow when it follows the selected card, data-loading while it loads
hero-backdrop, backdrop-frame, hero-backdropsThe picture, the box holding it, and the layer of them all in the rotating hero, which scrolls at half speed
hero-shadeThe shading over the picture; data-name is side or bottom
hero-content, hero-logo, hero-title, hero-overviewThe text part, the logo or title, and the description
hero-metaThe line of facts; each has data-name (year or episode, score, genres), with a meta-separator between
hero-actions, hero-actionThe buttons; data-name is play or info
hero-dots, hero-dotThe dots for each title; data-current marks the one showing
hero-rowsThe rows scrolling under the banner when it follows the selected card
hero-cornerThe picture in the top corner, when the banner keeps to the corner
hero-trailerThe box a title's trailer plays in, at the banner's end

Title pages

SelectorWhat it is
item-pageThe page; data-type is Movie, Series or BoxSet. States: data-watched, data-favourite
item-backdrop, item-backdrop-image, item-backdrop-shadeThe backdrop, its picture (data-wash when a blurred poster stands in) and its shading (data-name is side or bottom)
item-trailer, item-trailer-hintThe title's trailer playing behind the whole page, with its shading, and the line over it naming it (data-name playing) and how to open the player (data-name controls)
item-body, item-headerEverything over the backdrop, and the top part
item-poster, item-logo, item-title, item-tagline, item-next-airing, item-genres, item-genre, item-details, item-detailThe parts of the header, and the details list; each detail has data-name (studios, released, airs, country)
item-metaThe line of facts; each has data-name (year, age-rating, runtime, score, status), with a meta-separator between
item-actions, item-actionThe buttons; data-name is play, restart, trailer, random, party, play-on, add-to-playlist, watched, favourite, drop, rating, download (a show's) or more, and data-active marks watched, favourited, dropped or rated
item-quick-actions, item-quick-action, item-more-actionOn a phone, the row under Play and each labelled action in it, by the same data-name (data-shown on the three it shows), and the actions in More's list
download-button, download-menuA movie's or an episode's download button, and a show's download menu. data-state on the button is finding, needs-version, queued, downloading, paused, failed, done or sent once there is a download
rating-picker, inline-ratingThe box to rate a title, and a season's rating beside its summary; data-active once rated
item-actions-dividerThe line before the links to other sites
overview, overview-more, overview-popover, overview-banner, overview-textA description, its More link and the full text it opens
external-links, external-linkThe links to other sites, and each link; data-name is the site, such as imdb, tmdb, thetvdb, trakt, anidb or myanimelist
season-poster, season-name, season-indicator, season-pills, season-pillA season to pick, its name and the bar under the open one's, and the row of season buttons; data-selected marks the open one
season-summary, season-overviewThe season's year and episode count, and its description
episode-card, episode-list-item, episode-listAn episode in a row or a list. States: data-watched, data-in-progress, data-highlighted (the one you came to), data-unaired (not aired yet, whether or not it can play), and data-unavailable (unaired or missing, for one that can't)
episode-image, episode-play, episode-number, episode-status, episode-head, episode-title, episode-synopsisThe parts of an episode
episode-metaThe line of facts under its title; each has data-name (aired, length, rating), with a meta-separator between
episode-actions, episode-actionThe button beside an episode's title that opens its menu (data-name is menu), with its download-button once it has a download. On a TV, an episode that can't play yet has details instead
person-card, person-card-image, person-card-name, person-card-roleSomeone in the cast or crew
person-header, person-photo, person-datesA person's page

Versions

SelectorWhat it is
dialog[data-name='versions']The version list's dialog box
versions-banner, versions-header, versions-count, versions-listThe parts of the list
versions-actionThe buttons at the top; data-name is details or search-again
versions-start, versions-filter, versions-download-hintThe choice between resuming and starting over, the box to filter versions, and the note when you pick one to download
versionOne version; data-playing marks the one playing, data-cached a cached one
version-play, version-play-iconThe part you press to play it, and its play icon
version-name, version-description, version-playingIts title, the lines under it, and the Playing label
version-action, version-menuIts buttons, and the menu that holds them on a phone; data-name is copy-link or download
version-noticeA message instead of a version; data-type says what kind
versions-quick, versions-quick-filterThe row of quick filters, and one of them; aria-selected marks the one picked, data-count holds how many versions it finds, and data-empty marks one that finds none
version-badges, version-badgeA version's badges, and one of them

Player

SelectorWhat it is
videoThe video, in a browser
player-controlsEverything over the video. States: data-visible while the controls show, data-paused, data-waiting while it loads
player-top-bar, player-title, player-bottom-bar, player-middle, player-time, player-clockThe bars and the middle buttons, and the time of day in the top bar. The title's lines have data-name: name, and detail under it for an episode or a trailer
player-top-end, player-window-buttonsThe group at the end of the top bar, and in it, in the desktop app, the window buttons, which stand in for window-controls unless the player is full screen or a dialog is open; each has data-name as there
player-buttonA button in the bars; data-name is exit, mini-player, lock, play, back, forward, previous, next, mute, episodes, subtitles, chapters, versions, audio, speed, fit, statistics, party or fullscreen
player-middle-buttonA button in the middle, on phones and touch screens; data-name as above
player-menu, player-menu-itemThe list a button opens; data-name says which (subtitles, audio, speed, statistics), and data-selected marks the chosen item. An audio or subtitle track shows its language and kind, and its own title, often a release name, is the line with data-name="detail"
player-menu-action, player-menu-pagesAn item beside a list's choices (data-name is add-file, more for the languages not in your settings, or the page it opens), and the rows of pages above the list
player-menu-pageA page a list opens into; data-name is timing or style for the subtitles, sound for the audio. Its back button is player-menu-action with data-name="back"
player-sync-statusHow the subtitles were synced, on their timing page; data-status is hand, synced, retimed, unmatched or speed
volumeThe volume button and slider
volume-bar, volume-track, volume-level, volume-thumb, volume-valueThe slider, its filled part, its handle and the level as a number
volume-boost, volume-boost-levelPast 100%, where the desktop app can make it louder, and the red over the filled part that deepens the louder it gets
seek-bar, seek-bar-track, seek-bar-buffered, seek-bar-progress, seek-bar-thumb, seek-bar-tooltipThe timeline
seek-bar-thumbnailIn the apps, the picture over the timeline of the point you're on
seek-bar-segment, skip-segmentAn intro, recap or credits mark, and the button to skip it; data-type is Intro, Recap, Outro, Preview or Commercial
seek-bar-chapterA tick where a chapter starts, in the desktop app
play-flash, seek-flash, player-noticeWhat pops up on play, pause, skipping and subtitle changes
player-scrub, player-held-speedOn a touch screen, the time while you swipe to seek, and the speed while you hold for faster playback
player-lock, player-unlockThe locked screen on a touch screen, and its button to unlock
next-episode-card, next-episode-image, next-episode-action, next-episode-countdownThe next episode's card near the end; its buttons have data-name play or hide
still-watching, still-watching-image, still-watching-actionThe check that you're still watching; its buttons have data-name continue or back
player-episodes-header, player-episodes-seasons, player-episodes-list, player-episodeThe player's episode list, dialog[data-name='episodes']; data-current marks the one playing, and each has the states of episode-card and holds an episode-image and an episode-title
player-chapters-header, player-chapters-list, player-chapter, player-chapter-imageThe player's chapter list, dialog[data-name='chapters'], with a picture of each where the app makes them; data-current marks the one playing
sync-by-ear, sync-lines, sync-lineSubtitle syncing; data-closest marks the line nearest now
player-cover, player-cover-image, player-errorWhat shows while a video loads, and when it fails
player-cover-logo, player-cover-title, player-cover-detail, player-cover-barOn that cover, the logo, or the title when there's none, the episode's line under it, and the loading bar
pause-screenWhat shows over the dimmed picture once the video has stayed paused for a few seconds; data-visible while it shows
pause-logo, pause-title, pause-episode, pause-episode-title, pause-overviewOn it, the logo, or the title when there's none, an episode's season and number, its title, and the synopsis
player-statsThe statistics in the Android app when it plays with ExoPlayer, which draws none of its own
player-subtitleSubtitles in the Samsung TV app, where the page draws them
subtitle-dropWhat shows while a file is dragged over the player
player-externalIn the desktop app, the note that the video plays in your own player's window
mini-playerThe mini player, over the pages; data-mode is card, in a corner (data-corner is top-start, top-end, bottom-start or bottom-end), or bar, above the navigation on a narrow screen
mini-player-video, mini-player-imageWhere the video shows, and the title's picture there before it starts or while something covers it
mini-player-strip, mini-player-titleThe part under the video, or beside it in the bar, and the title in it, which opens the player again; its lines have data-name name and detail
mini-player-buttonIts buttons; data-name is play, pause or close
mini-player-progress, mini-player-progress-fillHow far through the video it is, and the filled part

Watch parties

SelectorWhat it is
dialog[data-name='party']The watch party panel
party-sectionA part of the panel; data-name is start, join, preview, invite, now-playing, members, host, overlay or leave
party-relay, party-listing, party-previewBefore joining: a relay to start on, a party on your server, and the party a code finds
party-tabs, party-unreadThe Chat and People and invite tabs (data-name is chat or party), and the count of unread messages
party-connection, party-watch-alongThe note while the party connects or reconnects, and the one to go back to what the party is watching
party-code, party-qrThe invite code and its QR code
party-memberSomeone in the party. States: data-you, data-host, data-away (their connection dropped), data-buffering
party-chat, party-message, party-reactionThe chat, a message in it, and a reaction button. A message has data-you when it's yours, and data-status (sending or failed) until it's sent
party-layer, party-status, party-actionWhat shows over the video: who the party is waiting for, and who paused, jumped or started something
party-bubbles, party-bubble, party-reactions, party-reaction-sentMessages over the video and each one, and the reactions rising over it and each one

Other pages

SelectorWhat it is
search-input, search-voice, search-suggestions, search-suggestion, search-history, search-history-item, search-history-menu, search-resultsThe search page: the box to search and its voice search button (data-listening while it listens), the titles suggested as you type, your past searches and the menu each opens, and the results
trailers-list, trailer, trailer-bar, trailer-embedA title's trailers in their dialog, and in a browser, the bar above YouTube's player and the player itself. The bar's buttons have data-name exit, previous or next
discover-label, discover-countBeside Discover's title, the kind or genre shown, and the number of titles
discover-filters, catalog-picker, genre-pills, genre-pill, genre-pickerDiscover's filters: the catalog picker, and the genres as buttons or, when there are many, a picker
calendar-grid, calendar-agenda, calendar-day, calendar-entryThe calendar as a month or a list; data-today marks today, data-watched a watched episode
calendar-nav, calendar-month, calendar-todayThe month buttons (data-name is previous or next), the month shown, and Today
live-tv, channel-list, channel-row, live-side, live-preview, channel-details, live-watch, live-favourite, channel-later, docked-playerLive TV: a group's channels (data-active on the one the keys are on, data-playing on the one playing), the preview the playing video fills, and the channel's programmes
guide, guide-ruler, guide-row, guide-channel, guide-cell, guide-now, live-top, programme-detailsLive TV's guide: a day of programmes by channel (data-airing and data-active on cells), the now line, and the programme above it
live-group-pickerThe searchable list of an addon's groups, when there are too many for pills. The pills are pill-tabs named live-group and live-view
live-from-start, live-day-pickerFrom the start, on a programme its channel keeps (its guide cell has data-catchup), and the list of the guide's days
player-live, live-pill, channel-number, previous-channelA channel in the player: the programme in place of the seek bar, the Live pill (data-behind after a pause), a typed number, and the channels sheet (a dialog named channels)
live-remindRemind me on a later programme (data-active once set); its guide cell has data-reminder, and the reminder as it starts is a dialog named reminder
channel-numberThe channel number being typed with a remote's digits, over the player or Live TV
history-day, history-tiles, history-tile, history-entry, history-entry-menu, history-table, history-view, user-chipsThe activity page; data-open marks an expanded tile
downloads-summary, downloads-actionThe downloads page's size and folder, and its buttons; data-name is open-folder, change-folder, open-app, pause-all, resume-all or delete-all
downloads-section, downloads-showA group of downloads (data-name is running, attention, sent or done), and a show's episodes in it
download, download-image, download-title, download-version, download-statusA download and its parts; data-state as on download-button
download-actionA download's buttons; data-name is pause, resume, retry, pick, folder or more
settings-tabs, settings-tab-group, settings-tab, settings-panel, settings-donateThe settings tabs, their groups (data-name is watching or app), each tab and its page (data-name such as playback, subtitles, theme or about), and Donate
settings-header, settings-header-description, settings-card, settings-card-title, settings-card-description, settings-card-body, settings-card-item, theme-preset, custom-css-editor, language-listA tab's page. Each card has a data-name from its title, such as next-episode, and each line in it is a settings-card-item
auth-card, user-picker, user-picker-user, servers, server, server-status, sign-in-links, quick-connect-codeSigning in, choosing a user and choosing a server; the buttons to the other screens, and the Quick Connect code
no-catalogs-tipThe tip on where to find catalogs, when you have none
no-details, no-details-tipWhat a title's page shows instead when no addon has details for it, and its tip on where to find one
report-sent, report-codeAfter sending a report, the message and the code to pass on
quick-filter, quick-filter-import, badge-packs, badge-pack, own-badges, own-badge, badge-import, badge-try, badge-formIn the quick filters and badges editors: a filter, adding filters from text, the badge packs and each one, your own badges and each one, adding badges from text, trying badges on a name, and the form to edit one
shortcuts-help, shortcut-keys, key-capsThe shortcuts list ? opens, a shortcut's keys in settings, and the keys shown for one

Shared components

Menus, dialogs, buttons and form controls come from a shared set of components. Their parts carry a class named UI-<Component>__<part>, kept stable like the data-ui names:

ClassWhat it is
.UI-Modal__content, __overlay, __header, __title, __description, __closeA dialog box and its parts
.UI-DropdownMenu__root, __item, __label, __separatorA menu
.UI-ContextMenu__root, __item, __label, __separatorA right-click menu
.UI-Tooltip__root, .UI-Popover__root, .UI-HoverCard__rootTooltips and popups
.UI-Button__root, .UI-IconButton__rootButtons
.UI-Badge__rootA small label, such as a genre
.UI-Input__root, .UI-Textarea__root, .UI-Select__root, .UI-Switch__rootForm controls
.UI-Card__rootA panel
.UI-VerticalMenu__itemA sidebar item
.UI-Carousel__itemA card's slot in a row
.UI-Skeleton__rootA placeholder while something loads

A message that fills a page or a row, such as an error or an empty catalog, is [data-luffy-error], with [data-luffy-error-image], [data-luffy-error-title] and [data-luffy-error-content] for its parts.

The popup messages use [data-sonner-toaster] for their container and [data-sonner-toast] for each one, with data-type set to success, error, warning or info.

Colours

The theme's colours are CSS variables, which you can set in your CSS as well. Those holding an R G B triple are used as rgb(var(--color-brand-500)), or rgb(var(--color-brand-500) / 0.5) to make them see-through.

VariableWhat it is
--color-brand-50 to --color-brand-950The accent's shades, as R G B
--color-gray-50 to --color-gray-950The background's shades, used by panels and text, as R G B
--backgroundThe page's colour
--paperThe colour of menus and dialogs
--foreground, --muted, --muted-highlightText, dimmed text, and dimmed text on hover
--border, --ringBorders, and the ring around what has keyboard focus
--subtle, --subtle-highlightFaint fills, such as behind a hovered item
--brandAccent-coloured text
--radius, --radius-mdCorner rounding of menus and inputs
--red, --orange, --green, --blue and the likeNamed colours for text

On this page