> ## Documentation Index
> Fetch the complete documentation index at: https://juo.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Web components

> The custom elements that wire blocks into the DOM — when to reach for each one.

`@juo/blocks` ships a small set of custom elements that connect block definitions to the page. These are the only `@juo/blocks` APIs called from HTML; everything else (services, contexts, signals) lives in JavaScript.

| Element                | Role                                                                                       |
| ---------------------- | ------------------------------------------------------------------------------------------ |
| `<juo-context-root>`   | Boundary for context providers and requests.                                               |
| `<juo-page>`           | Root page renderer. Resolves a route through `ThemeState` and renders the resulting block. |
| `<juo-extension-root>` | Slot fan-out. Renders the children a merchant placed into a named slot.                    |
| `<juo-block>`          | Declarative ad-hoc instance of a registered block, parameterized by HTML attributes.       |
| `<juo-text>`           | Inline text node. Read-only at runtime; editable inline in the editor.                     |

Two builds ship the same tag set:

* `@juo/blocks/web-components/runtime` — lean storefront elements.
* `@juo/blocks/web-components/editor` — same elements plus selection wrappers, drop zones, and inline-text editing.

Import one or the other from the portal entry. See [Editor](/docs/blocks/concepts/editor) for how the editor build layers on top.

## `<juo-context-root>`

Hosts the context tree. Providers call [`provideContext`](/docs/blocks/concepts/contexts#providing-a-context) against it; blocks below it call `injectContext` and the request is answered by the nearest root above the requester.

```html theme={null}
<juo-context-root>
  <!-- everything below resolves contexts from this root -->
</juo-context-root>
```

Nest a second root to override services for a sub-tree. See [Scoping and overrides](/docs/blocks/concepts/contexts#scoping-and-overrides) for the pattern and the typical uses (previews, workflow overlays, tenant scoping).

## `<juo-page>`

The root page renderer. Subscribes to `ThemeStateContext`, asks it to resolve a route, and renders the resulting first block reactively. When the theme state's blocks change — because the editor updated a prop, a translation flipped, or the route changed — the page re-renders automatically.

```html theme={null}
<juo-context-root>
  <juo-page route="/"></juo-page>
</juo-context-root>
```

**Attributes**

* `route` — *optional*. When set, the element calls `themeState.resolve(surface, route)` as soon as a `ThemeState` becomes available, and again whenever the attribute changes. Omit it to drive resolution from JavaScript (e.g. from a custom router).
* `surface` — *optional*. `"page"` (default) or `"overlay"`. Selects which `ThemeState` surface to render.

`<juo-page>` does not take a block name — what it renders is whatever `ThemeState.resolve()` returns for the given path. That keeps routing in one place (`RouterService` / theme state) instead of duplicated across markup.

## `<juo-extension-root>`

Renders the children placed into a named slot of the surrounding page's root block. Page renderers emit one `<juo-extension-root>` per slot they expose; the editor decorates each child with selection chrome via a wrapper.

```ts theme={null}
// Inside a page block's renderer
const container = document.createElement("div");
container.innerHTML = `
  <juo-extension-root name="header"></juo-extension-root>
  <juo-extension-root name="main"></juo-extension-root>
`;
return container;
```

**Attributes**

* `name` — *required*. The slot name to render. Must match a key in the page block's `slots` schema.
* `surface` — *optional*. `"page"` (default) or `"overlay"`. Selects which surface to read children from.

`<juo-extension-root>` reads from the same `ThemeState` that `<juo-page>` resolves, so nothing needs to be passed through props — child blocks just appear when the merchant places them in that slot.

## `<juo-block>`

Mounts a fresh ad-hoc instance of a registered block, parameterized by its HTML attributes. Useful for dropping a block into static markup — a one-off mount in a sidebar, a Storybook story, a hand-written page that isn't driven by theme state.

```html theme={null}
<juo-block name="SubscriptionList"></juo-block>
```

**Attributes**

* `name` — *required*. The registered block name (the value passed to `defineBlock`/`registerBlock`).
* Any other attribute is forwarded as a prop on the block's instance.

`<juo-block>` is **not** what renders pages from theme state — for that use `<juo-page>`. Use `<juo-block>` only to drop a block by name into markup independently of routing or stored slot composition.

## `<juo-text>`

An inline text node. In the runtime build it's a passive container — it shows its text content. In the editor build it becomes editable inline, with its content flowing through the theme state's translation catalog.

```html theme={null}
<juo-text key="cta-label">Manage subscription</juo-text>
```

Block renderers typically emit `<juo-text>` for any merchant-editable copy. See [Localization](/docs/blocks/concepts/localization) for how the key resolves against the active locale's catalog.

## Composition

A typical page rendered through the platform looks like:

```
<juo-context-root>           ← services and ThemeState provided here
  <juo-page route="/">       ← resolves the route, renders the root block
    <div>                    ← the root block's renderer output
      <juo-extension-root name="header"/>   ← slot fan-out
      <juo-extension-root name="main"/>
    </div>
  </juo-page>
</juo-context-root>
```

The root block, the children in each slot, the prop values, and the translations all come from the same `ThemeState` — the only thing pinned in markup is the route. Editing in the Juo Editor updates the theme state; everything below `<juo-page>` re-renders automatically.

`<juo-block>` doesn't appear in this tree because page rendering goes through theme state, not through ad-hoc instances. Use `<juo-block>` only for a one-off mount that is not part of an editable page.
