Radiant0.3.0-rc.12

@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

OptionTypeDescription
contextContextThe typed context token to provide
initialValueTInitial provider value
hydrateString | Number | Boolean | Object | ArraySerializes and restores provider state during SSR hydration
serialize(value: T) => unknownProjects 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' },
	});
}