Subchapter 1.19
references/context-provider/EXAMPLES.mdMarkdown5 KBView on GitHub
Scaffold each provider with wix generate first (see the Quick Start Checklist); the examples show the finished files.
From the request “Create a counter that counts how many times a button was clicked and show a congratulations banner only when the count reaches 10. Use context providers and native components, do not create an editor react component.”
Every element here is a native Editor element, so every consumer is a binding-only consumer. count >= 10 cannot be evaluated at the binding, and neither can its negation — so the provider resolves both sides itself and exposes one ready-to-bind boolean per gated element. See Derived Values (Mandatory).
src/extensions/site/contexts/click-goal-context/click-goal-context.tsx:
import React, { createContext, useContext, useState } from 'react';
import type { BooleanValue, NumberType, Text } from '@wix/editor-react-types';
export interface ClickGoalContextType {
count: NumberType;
isCongratsBannerHidden: BooleanValue;
isProgressHintHidden: BooleanValue;
statusMessage: Text;
increment: () => void;
}
export interface ClickGoalProviderProps {
children?: React.ReactNode;
goal: NumberType;
}
const ClickGoalContext = createContext<ClickGoalContextType | null>(null);
ClickGoalContext.displayName = 'ClickGoalContext';
export function useClickGoalContext(): ClickGoalContextType {
const context = useContext(ClickGoalContext);
if (!context) {
throw new Error('useClickGoalContext must be used within a ClickGoalContextProvider');
}
return context;
}
export function ClickGoalContextProvider({
children,
goal,
}: ClickGoalProviderProps): React.ReactNode {
const [count, setCount] = useState<NumberType>(0);
const target = goal ?? 10;
const increment = (): void => {
setCount((current) => current + 1);
};
// Derived at render time from the state — never stored in a second state value.
const hasReachedGoal = count >= target;
const remaining = target - count;
const statusMessage = hasReachedGoal
? 'Goal reached'
: `${remaining} more ${remaining === 1 ? 'click' : 'clicks'} to go`;
const api: ClickGoalContextType = {
count,
isCongratsBannerHidden: !hasReachedGoal, // hidden until goal is reached
isProgressHintHidden: hasReachedGoal, // the complement, precomputed
statusMessage,
increment,
};
return (
<ClickGoalContext.Provider value={api}>{children}</ClickGoalContext.Provider>
);
}
ClickGoalContextProvider.displayName = 'ClickGoalContextProvider';
export default ClickGoalContextProvider;context, data and contextSpecifier in src/extensions/site/contexts/click-goal-context/click-goal-context.extension.ts (the rest of the file is generated by wix generate):
context: {
items: {
count: {
dataType: 'number',
displayName: 'Click count',
description: 'How many times the button has been clicked so far. Bind to a text element content.',
},
isCongratsBannerHidden: {
dataType: 'booleanValue',
displayName: 'Congratulations banner is hidden',
description: 'True while the click count is below the goal. Bind to the congratulations banner hidden property.',
},
isProgressHintHidden: {
dataType: 'booleanValue',
displayName: 'Progress hint is hidden',
description: 'True once the click count reaches the goal. Bind to the progress hint hidden property.',
},
statusMessage: {
dataType: 'text',
displayName: 'Status message',
description: 'Reads how many clicks remain, or confirms the goal was reached. Bind to the progress hint content.',
},
increment: {
dataType: 'function',
displayName: 'Count one click',
description: 'Adds one to the click count. Bind to the button click handler.',
function: {
parameters: [],
async: false,
},
},
},
},
data: {
goal: {
dataType: 'number',
defaultValue: 10,
deprecated: false,
displayName: 'Goal',
},
},
resources: {
contextSpecifier: {
hook: 'useClickGoalContext',
moduleSpecifier: '<moduleSpecifierPrefix>click-goal-context',
},
},The site owner binds the Button’s click handler to increment, the banner’s hidden property to isCongratsBannerHidden, the hint’s hidden property to isProgressHintHidden, and each text element’s content to count or statusMessage — the platform converts both to rich text at the binding.
No consumer component and no contextDependencies exist for this section — the provider registration above is the entire implementation.
useClickGoalContext is still exported and contextSpecifier.hook still registered — those are manifest requirements, not a consumer wiring. That is the rule in The Provider’s Shape Never Shrinks: “native elements only” constrains which consumers get written, never the provider’s shape.
Note also that every bindable item carries a description naming what to bind it to; see The Manifest Is the Binding Contract.