Skip to main content
Your component mounts in a shadow root. The host’s CSS variables inherit into it and your CSS cannot leak out. Write every colour, radius and font as a variable with a fallback and your surface follows the owner’s theme with no theme code.
Import that file from your entry. The build collects the stylesheets each entry reaches and the host injects them into your shadow root, ahead of your component.

The variables

Those fifteen are the whole list, and they are the same fifteen installHostTheme() sets in a test, so a component renders in a test the way it renders in the host. Always write a fallback: a variable the host has not set yet falls through to it rather than to nothing. Today the host sets a handful of these; the rest fall through to your fallback until the host theme lands. They change with the owner’s theme. useTapTheme() gives you { mode: "light" | "dark" } when a component has to branch rather than restyle — a chart’s series colours, say.

The UI kit already uses them

TapCard, TapStat, TapButton, TapTable and the rest of the kit are built on exactly this list, so a surface assembled from them needs no CSS of your own:

Two rules the checks read

  • No bundled fonts and no third-party stylesheets. A publish rejects a bundle that loads a font or a script from another origin. Use --font-sans and --font-mono. Writing a stylesheet into the document is a warning rather than a rejection, and the warning is worth acting on: styles put on document.head leave your shadow root and land on the host and on every other extension on the page. An emitted .css asset is a rejection, because a separate file never reaches a shadow root — the build inlines the stylesheets your entry imports, so that one does not fire on its own.
  • Container queries, not viewport queries. A slot’s width has nothing to do with the viewport. Your mount is the container, so size against it:
A widget has to be readable at 320 pixels. That is the width to design against.