Overview

Context<T> is a lightweight token (new Context()) with a unique id. It does not hold the live value — the value lives on an ancestor <x-provider> via .context and .value properties.

useContext(ctx) must run with an active component host (typically the outer function). It dispatches a bubbling request-context event; the nearest matching x-provider stops propagation and resolves with its .value. Missing provider → null (no throw).

vs scopes: scopes (scope(Class) / getParentScope) are class instances with atoms and methods — preferred for shared reactive UI state. Context is better for simple value injection (theme string, config object, or an atom reference) without defining a class.

Context vs scopes

Aspect
Context + x-provider
scope()
Provide <x-provider .context .value> scope(ScopeClass) in outer function
Consume useContext(ctx) getParentScope(Class)
Missing provider returns null throws at runtime
Best for Simple values / atom refs Atoms + methods + optional setup()
Nesting Closest provider wins Child scope shadows parent for same class

Provide and consume

Badge inside x-provider reads 'dark'. The sibling Badge outside the provider gets null and shows 'none'.

import { html, x, Context, useContext, renderApp } from 'mates';

const ThemeCtx = new Context();

const Badge = () => {
const theme = useContext(ThemeCtx);
return () => html`
<span class="tag tag-soft">theme: ${theme ?? 'none'}</span>
`;
};

const App = () => () => html`
<div class="m-col m-gap">
<x-provider .context=${ThemeCtx} .value=${'dark'}>
${x(Badge)}
</x-provider>
${x(Badge)}
</div>
`;

renderApp(App, document.getElementById('app'));

Share an atom via Context

Pass the atom itself as .value. Display and Controls both useContext(CountCtx) and read/write count() — reactive without a scope class.

import { html, atom, x, Context, useContext, renderApp } from 'mates';

const CountCtx = new Context();

const Display = () => {
const count = useContext(CountCtx);
return () => html`
<h1>${count()}</h1>
`;
};

const Controls = () => {
const count = useContext(CountCtx);
return () => html`
<button class="btn-primary" @click=${() => count.set(n => n + 1)}>+1</button>
`;
};

const App = () => {
const count = atom(0);
return () => html`
<div class="m-col m-gap">
<x-provider .context=${CountCtx} .value=${count}>
<div class="m-flex m-items-center m-justify-center m-gap-sm">
${x(Display)}
${x(Controls)}
</div>
</x-provider>
</div>
`;
};

renderApp(App, document.getElementById('app'));