@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>;
}See Typing Decorated Fields for the field type.
Options
| Option | Type | Description |
|---|---|---|
context | Context | The typed context token to provide |
initialValue | T | Initial provider value. Each provider shallow-copies a plain object or array; nested values are shared |
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 |
Updating Context
provider.setContext(update) merges update over the current object value one level deep. A top-level key in update replaces that key outright, so a nested object is overwritten, not merged: to change one field inside it, pass the whole nested object.
// context: { user: { name: 'Ada', age: 36 }, theme: 'light' }
provider.setContext({ user: { ...provider.getContext().user, name: 'Grace' } });When the current value or update is not a plain object (an array, string, number, boolean or null), update replaces the value instead. Subscribers and the callback still run.
// context: ['a']
provider.setContext(['a', 'b']);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);
}
}
type LoggedThemeContext = ThemeContext & { logger: ThemeLogger };
export const loggedThemeContext = createContext<LoggedThemeContext>(Symbol('logged-theme-context'));
@provideContext({
context: loggedThemeContext,
initialValue: { mode: 'light', logger: new ThemeLogger() },
hydrate: Object,
serialize: ({ mode }) => ({ mode }),
})
provider!: ContextProvider<typeof loggedThemeContext>;When hydrate: Object is active, the parsed payload merges back into initialValue one level deep, 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' },
});
}