The pre-paint theme setup — palettes plus the stamp script — renders in
<head>, before (or with) the stylesheets.
Every page class had its own first-paint story and most of them flashed:
the dashboard's <html> carried no data-theme and applied the saved one
from a script at the end of <body>; the standalone admin hardcoded
data-theme="light" and fixed it up on DOMContentLoaded; the kit's own
root layout hardcoded light and ran no theme JS at all. A dark-mode user
got a white flash on the first two and permanent light on the third.
This component is the one shared answer: the custom-theme <style>
(phoenix- plus host :theme_definitions) plus a synchronous script that
reads the saved choice, resolves "system" from ThemeConfig.system_pair/0
— the CONFIGURED pair, not hardcoded `phoenix-names — and stampsdata-themepluscolor-schemeon<html>before the first paint. The palettes travel with the stamp: a script-only bootstrap on a host layout (or the standalone admin shell) used to paintphoenix-dark+color-scheme: darkover daisyUI's light variables until a later<style>`
in the body arrived.
It also subscribes to the storage event, so a theme picked in one tab
follows into the others.
Host root layouts can render it too (PhoenixKitWeb.Components.ThemeBootstrap
is public API); a host with its own equivalent script loses nothing by
keeping it.
Summary
Functions
The blocking head setup (palettes + stamp script). Render in <head>.