@provideContext
Use @provideContext(...) to attach a context provider to a host.
It works on both RadiantElement and RadiantController hosts.
Example
import { RadiantElement, customElement } from '@ecopages/radiant';
import { createContext, provideContext, type ContextProvider } from '@ecopages/radiant/context';
type ThemeContext = {
mode: 'light' | 'dark';
};
export const themeContext = createContext<ThemeContext>(Symbol('theme-context'));
@customElement('theme-provider')
export class ThemeProvider extends RadiantElement {
@provideContext<typeof themeContext>({
context: themeContext,
initialValue: { mode: 'light' },
})
provider!: ContextProvider<typeof themeContext>;
}Options
| Option | Type | Description |
|---|---|---|
context | Context | The typed context token to provide |
initialValue | T | Initial provider value |
hydrate | String | Number | Boolean | Object | Array | Serializes and restores provider state during SSR hydration |
serialize | (value: T) => unknown | Projects the live context into an SSR-safe hydration payload |
SSR Hydration
When hydrate is set, the provider can restore its context value from server-rendered hydration data.
@provideContext({
context: themeContext,
initialValue: { mode: 'light' },
hydrate: Object,
})
provider!: ContextProvider<typeof themeContext>;Use serialize(...) when the live client context includes members that should not be emitted into SSR JSON.
class ThemeLogger {
log(message: string) {
console.log(message);
}
}
@provideContext({
context: themeContext,
initialValue: { mode: 'light', logger: new ThemeLogger() },
hydrate: Object,
serialize: ({ mode }) => ({ mode }),
})
provider!: ContextProvider<typeof themeContext>;When hydrate: Object is active, the parsed payload merges back into initialValue, so omitted client-only members keep their defaults.
When Radiant owns SSR for the host, prefer renderComponent(...) so hydration scripts are emitted as raw markup. Those SSR helpers live under @ecopages/radiant/server/*. Avoid placing JSON strings directly inside <script> children in JSX, because they will be HTML-escaped before the browser parses them.
For the full server-plus-client host hydration flow, including the explicit client hydrator requirement, see Hydration.
Access From Descendants
Any descendant can resolve that provider through @consumeContext, bind a field to it through @contextSelector, or react to it with a method through @onContextUpdate.
RadiantController Example
import { RadiantController } from '@ecopages/radiant';
import { createContext, provideContext, type ContextProvider } from '@ecopages/radiant/context';
type ThemeContext = {
mode: 'light' | 'dark';
};
export const themeContext = createContext<ThemeContext>(Symbol('theme-context'));
export class ThemeController extends RadiantController {
@provideContext<typeof themeContext>({
context: themeContext,
initialValue: { mode: 'light' },
})
provider!: ContextProvider<typeof themeContext>;
}Manual Provider Construction
If you need lower-level control, you can still construct ContextProvider yourself.
import { RadiantElement } from '@ecopages/radiant';
import { ContextProvider } from '@ecopages/radiant/context';
class ThemeHost extends RadiantElement {
provider = new ContextProvider<typeof themeContext>(this, {
context: themeContext,
initialValue: { mode: 'light' },
});
}