From 826e3104dc34fb6e64a3029436ffa8c9a6a13012 Mon Sep 17 00:00:00 2001 From: Iulian Meghea Date: Mon, 7 Sep 2026 14:41:51 +0000 Subject: [PATCH 1/2] =?UTF-8?q?docs:=20add=20Styling=20guide=20=E2=80=94?= =?UTF-8?q?=20adopted=20style=20sheets,=20css=20helper,=20CSS=20modules?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - New guides/styling page covering inline +
Hello!
+ `; +} + +customElements.define('my-app', component(App)); +``` + +This works fine for small components, but the browser parses the stylesheet once per element instance. For shared styles or components rendered many times, prefer adopted style sheets. + +## Adopted style sheets + +pion supports [constructable stylesheets](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM#applying_styles_inside_the_shadow_dom) through the `styleSheets` option. Sheets are constructed once and adopted by every instance of the component: + +```js +import { component, html, css } from '@pionjs/pion'; + +const style = css` + :host { + display: block; + padding: 1rem; + } + .content { + color: var(--my-app-color, currentColor); + } +`; + +function App() { + return html`
Hello!
`; +} + +customElements.define('my-app', component(App, { styleSheets: [style] })); +``` + +`styleSheets` accepts a mix of strings and `CSSStyleSheet` instances — strings are converted to stylesheets automatically. + +:::tip[Recommended pattern] +Define styles in a dedicated file next to your component (e.g. `my-app.style.ts`) and import it. This keeps the component function focused on behavior and makes styles reusable: + +```js +// my-app.style.ts +import { css } from '@pionjs/pion'; + +export const style = css` + :host { display: block; } +`; +``` + +```js +// my-app.ts +import { component, html } from '@pionjs/pion'; +import { style } from './my-app.style'; + +customElements.define('my-app', component(App, { styleSheets: [style] })); +``` +::: + +### The `css` tagged template + +`css` is a tagged template that returns a plain string. It supports interpolation, which makes it easy to compose styles or build themes from parts: + +```js +import { css } from '@pionjs/pion'; + +const base = css` + :host { display: block; } +`; + +const theme = css` + :host { --my-app-color: rebeccapurple; } +`; + +export const style = css` + ${base} + ${theme} + .content { color: var(--my-app-color); } +`; +``` + +:::caution +Since `css` returns a string, interpolating a value like `0` or `false` results in an empty string (falsy values are dropped). Coerce interpolated values to strings when in doubt. +::: + +### Attaching styles to the renderer function + +Instead of the options object, you can set `styleSheets` as a static property on the component function itself: + +```js +function App() { + return html`
Hello!
`; +} + +App.styleSheets = [style]; + +customElements.define('my-app', component(App)); +``` + +If both are provided, the renderer's `styleSheets` take precedence over the ones passed to `component()`. + +### The `sheet()` helper + +If you need a `CSSStyleSheet` directly (for example to adopt it on a document or another shadow root), use the `sheet` helper: + +```js +import { sheet } from '@pionjs/pion'; + +const styles = sheet(':host { display: block; }', '.content { color: red; }'); + +document.adoptedStyleSheets = [...document.adoptedStyleSheets, styles]; +``` + +## Native CSS modules + +With the [CSS modules](https://developer.chrome.com/docs/css-ui/css-modules) import attribute (`with { type: 'css' }`), the browser hands you a ready-made `CSSStyleSheet`. Since `styleSheets` accepts existing instances, they work out of the box: + +```js +import { component, html } from '@pionjs/pion'; +import styles from './my-app.css' with { type: 'css' }; + +function App() { + return html`
Hello!
`; +} + +customElements.define('my-app', component(App, { styleSheets: [styles] })); +``` + +Bundler notes: + +- **Vite** and **Rollup** support `with { type: 'css' }` — the imported value is a constructed stylesheet that adopts cleanly into shadow roots. +- This syntax requires a modern browser or a bundler that transforms it; it does **not** work from a plain `