Customize Creator UI
Use your design system, vocabulary, theme, and property editors without forking Kajay.
Use design-system components
Pass a partial Creator component map to replace buttons, inputs, selects, checkboxes, textareas, and menus. Missing entries keep the Kajay defaults.
import type { CreatorComponents } from '@kajay/creator-react';
const creatorComponents = {
Button: DesignSystemButton,
Input: DesignSystemInput,
Select: DesignSystemSelect,
Checkbox: DesignSystemCheckbox,
Textarea: DesignSystemTextarea,
Menu: DesignSystemMenu,
} satisfies CreatorComponents;
<SurveyCreator
value={definition}
onChange={setDefinition}
components={creatorComponents}
surveyComponents={surveyComponents}
/>Creator chrome and the previewed survey use separate component maps. Pass components for Creator controls and surveyComponents for the survey renderer.
Customize words and theme
Register only the Creator strings you want to replace; all other messages retain their built-in values. Creator locale is separate from the survey locale, and creatorTheme styles the tool rather than the survey being designed.
import { CreatorStringDictionary } from '@kajay/creator-core';
const strings = new CreatorStringDictionary();
strings.register('en', {
tabDesign: 'Build',
tabPreview: 'Try it',
addPage: 'Add a section',
toolboxSearch: 'Find a field',
});
<SurveyCreator
value={definition}
onChange={setDefinition}
strings={strings}
locale="en"
creatorTheme={{ '--kajay-color-accent': '#6d28d9' }}
/>Replace a property editor
Use a resolver when a deployment knows more about a property than its registered primitive type. A resolver can match a property name, an editor kind, or both.
import {
PropertyEditorProvider,
useCreatorComponents,
} from '@kajay/creator-react';
import type {
PropertyEditorProps,
PropertyEditorResolver,
} from '@kajay/creator-react';
function TitleLocationEditor(props: PropertyEditorProps) {
const { Select } = useCreatorComponents();
const { surface, element, row, id, hint, testId } = props;
return (
<Select
id={id}
aria-describedby={hint}
data-testid={testId}
value={typeof row.value === 'string' ? row.value : 'default'}
options={['default', 'top', 'left', 'hidden'].map((value) => ({
value,
label: value,
}))}
onValueChange={(value) => {
surface.setProperty(element, row.name, value);
}}
/>
);
}
const resolveEditor: PropertyEditorResolver = (row) =>
row.name === 'titleLocation' ? TitleLocationEditor : undefined;
<PropertyEditorProvider resolve={resolveEditor}>
<SurveyCreator value={definition} onChange={setDefinition} />
</PropertyEditorProvider>Put the supplied id on the control and wire aria-describedby to the supplied hint. Write through the provided design surface so restrictions, undo, serialization, and notices remain intact.