diff --git a/__tests__/html-parser/__snapshots__/render-to-html.test.tsx.snap b/__tests__/html-parser/__snapshots__/render-to-html.test.tsx.snap
index 2c96c8d..302a49d 100644
--- a/__tests__/html-parser/__snapshots__/render-to-html.test.tsx.snap
+++ b/__tests__/html-parser/__snapshots__/render-to-html.test.tsx.snap
@@ -112,6 +112,21 @@ exports[`renderToHTML should correctly render jsx with arrays in between element
"
`;
+exports[`renderToHTML should properly handle context data Provider and Consumer 1`] = `
+"
+
+
+
no value
+
no value
+
FOO
+
FOO
+
BAR
+
BAR
+
+
+"
+`;
+
exports[`renderToHTML should properly handle context data close-by providers should not interfere with each other 1`] = `
"
diff --git a/__tests__/html-parser/render-to-html.test.tsx b/__tests__/html-parser/render-to-html.test.tsx
index df38ccc..d9182a7 100644
--- a/__tests__/html-parser/render-to-html.test.tsx
+++ b/__tests__/html-parser/render-to-html.test.tsx
@@ -798,6 +798,50 @@ describe("renderToHTML", () => {
expect(html).toMatchSnapshot();
});
+
+ it("Provider and Consumer", () => {
+ const MagicalContext = defineContext();
+
+ const Foo: JSXTE.Component<{ id: string }> = (props, { ctx }) => {
+ const value = ctx.get(MagicalContext) ?? "no value";
+ return (
+
+ {value}
+
+ );
+ };
+
+ const App = () => {
+ return (
+
+
+
+
+ {v ?? "no value"}}
+ />
+
+
+ {v}}
+ />
+
+
+ {v}}
+ />
+
+
+
+
+
+ );
+ };
+
+ const html = renderToHtml();
+
+ expect(html).toMatchSnapshot();
+ });
});
describe("ErrorBoundary", () => {
diff --git a/src/component-api/component-api.ts b/src/component-api/component-api.ts
index 287b41d..24cf126 100644
--- a/src/component-api/component-api.ts
+++ b/src/component-api/component-api.ts
@@ -3,6 +3,7 @@ import {
jsxElemToHtmlSync,
type RendererInternalOptions,
} from "../html-parser/jsx-elem-to-html";
+import { jsx } from "../jsx-runtime";
export class ContextAccessor {
public static clone(original: ContextAccessor): ContextAccessor {
@@ -146,6 +147,26 @@ export class ComponentApi {
export class ContextDefinition {
id = Symbol();
+
+ Provider = (
+ props: JSXTE.PropsWithChildren<{
+ value: T;
+ }>,
+ componentApi: ComponentApi
+ ) => {
+ componentApi.ctx.set(this, props.value);
+ return jsx("", { children: props.children });
+ };
+
+ Consumer = (
+ props: JSXTE.PropsWithChildren<{
+ render: (value?: T) => JSX.Element;
+ }>,
+ componentApi: ComponentApi
+ ) => {
+ const value = componentApi.ctx.get(this);
+ return props.render(value);
+ };
}
export const defineContext = () => new ContextDefinition();