Hook reference

Every stable data-* selector Signal exposes for Code injection — regions, components, variants, and parts — plus the protected names you must not rename.

The complete list of Signal's stable styling handles. These names don't change between theme updates, so you can build Code-injection CSS against them with confidence. See Code injection for how the system works.

Regions — data-region

A structural area, usually one per page.

ValueWhere
site-header, masthead, primary-nav, mobile-navThe header and its menus
hero, hero-bodyThe homepage hero
platformsThe "Watch & listen on" band
featured-episodes, episode-feedHomepage episode sections
from-blog, blog-feedThe homepage "From the blog" band and the /blog/ index
hosts, guests, guests-index, frequent-guestsHost & guest sections and the directory
about, sponsors, membershipHomepage about / sponsors / support sections
contact-hero, contact-reasonsThe Contact page
archive-headerThe heading band on the /blog/, topic, and author archives
post / page, page-bodyAn episode, a blog post, or a generic page
post-header, post-media, post-bodyThe post header, the episode player area, and the body (post-media is episodes only)
comments, newsletterThe comments and newsletter areas
library, error / error-suggestionsThe Library page and error pages
site-footer, footer-navThe footer

Components — data-component

A reusable unit that can appear many times.

ValueWhat
episode-row, episode-cardEpisode list rows and cards
article-row, article-cardBlog-post rows and cards (the written-content counterparts of the episode ones)
blog-byline, author-bio, more-from-blogA blog post's byline, end-of-article author card, and related-articles row
guest-card, host-card, guest-ctaPeople cards and the "be a guest" prompt
author-socials, social-linksSocial icon rows
play-buttonThe play affordance
platform-listA listen-links mount
sponsors, tier-list, tier-cardSponsor logos and membership tiers
contact-form, newsletter-ctaThe contact and newsletter forms
filter-chips, episode-tabs, paginationTopic filters, episode tabs, pagination
footer-brand, footer-legalFooter blocks

Variants — data-variant

A flavour of its host component or region.

HostValues
herolatest, podcast, host, listen, cinematic — the homepage hero layout (set by the Home hero setting)
postblog on a #blog written post; an episode carries no variant
post-headeraudio on #audio episodes, embed on #embed episodes; a default video episode header carries no variant
archive-headerblog on the /blog/ index, tag on a topic archive
error404

Parts — data-part

A piece inside a component or region. The core names are the same everywhere.

ValueWhat
title, kicker, excerpt, meta, image, read-timeThe shared core (any preview, header, or card)
logo, wordmarkThe brand logo image and the brand link/text
author, role, duration, episode-numberEpisode and people details
descriptionA row's summary line (episode and article rows)
poster, transcript, chaptersThe media poster and the transcript/chapters content

Scoping a part

Parts repeat, so scope them to a region or component: [data-component="article-row"] [data-part="title"] targets only blog-row headlines, not every title on the page.

Protected hooks

These are theme-owned functional names that the player, transcript, Library, comments, and navigation depend on. You may read and style them, but renaming, moving, or removing them — or wrapping the player host — breaks playback, cross-page continuity, transcript seeking, the Library, or comments.

Don't build CSS that relies on changing these; treat them as read-only structure:

  • Player: #mp-player-host (and its data-mode / data-mp-position / data-mp-* attributes), #mp-live, #mp-progress, #main-content, .mp-focus-target. Never wrap or reparent the player host.
  • Media stage: [data-mp-stage], data-mp-source-scope, data-mp-key, data-poster.
  • Transcript & chapters: [data-transcript-empty] / -ready / -scroll / -search, [data-autoscroll-toggle], [data-chapters-empty] / -ready / -count / [data-chapters], [data-seek-seconds].
  • Comments: [data-lazy-comments-mount], [data-lazy-comments-template].
  • Listen links: [data-signal-platforms], [data-signal-listen-links], [data-signal-listen-section], [data-listen-built].
  • Library: [data-library-toggle], [data-library-widget] / -trigger / -panel / -tab / -list / -count, [data-library-page] (and its post-hydration [data-hydrated] flag) / -section / -rows / -empty / -clear.
  • Navigation & state: the nav menu attributes, [data-set-theme], the pre-hydration [data-nav-pending] gate on the header menu, and the [data-nav-collapsed] / [data-color-scheme] state on <html> (select on these, never override).

Pre-hydration guards (avoiding flash)

Signal is built to render cleanly on the very first paint, before its JavaScript runs. A few elements are therefore held by CSS until the scripts hydrate them, so they never flash in a half-finished state. Every guard is gated on the js class (added to <html> before paint, so a no-JS visitor always sees the full content) and released by a 2.5-second failsafe if the bundle ever fails to load — nothing can get stuck hidden.

Held until hydratedHow it's heldReleased by
Desktop header menu — the overflow "More" pass[data-nav-pending] on the [data-region="primary-nav"] list → visibility: hiddennavigation.js, once it has measured the bar and built "More"
Library empty states on /library/[data-library-page]:not([data-hydrated]) [data-library-empty]display: nonelibrary.js, once it has read your saved items
Below-the-fold sections[data-reveal] → hidden until scrolled into viewreveal.js (IntersectionObserver)
Episode show-notes source blocks — raw transcript/chapter code and the duplicated media card.js [data-component="episode-tabs"] .gh-content …display: nonethe player scripts, which lift them into the hero and tabs

Don't force any of these visible from Code injection (for example visibility: visible on the pending nav, or display: block on [data-library-empty]). Overriding a guard re-introduces the exact flash it prevents — style the settled result instead.

Adding a hook

If you need a hook that isn't here, it can be added to the theme (and documented on this page). Renaming or removing an existing one is a breaking change. See For developers.