Creating New Components
Adding a new component requires two things: a Content Model in the CMS (the schema) and a React component in your storefront (the renderer). They’re linked by the model’s api_id.
Step-by-step example
This walkthrough adds a TestimonialCard component.
-
Create the content model in Alokai CMS
Go to Content Models → New Content Model:
Setting Value Name Testimonial CardAPI ID TestimonialCardType ComponentAdd these fields:
Name Type quoterichtext authortext roletext avatarimage Save the model.
-
Create the React component
In your storefront, create
components/cms/page/testimonial-card.tsx:interface TestimonialCardProps {quote: string;author: string;role?: string;avatar?: { url: string; alt: string };className?: string;}export default function TestimonialCard({ quote, author, role, avatar, className }: TestimonialCardProps) {return (<figure className={className}><blockquote dangerouslySetInnerHTML={{ __html: quote }} /><figcaption>{avatar && <img src={avatar.url} alt={avatar.alt} />}<strong>{author}</strong>{role && <span>{role}</span>}</figcaption></figure>);} -
Register it in
render-cms-content.tsxOpen
components/cms/page/render-cms-content.tsxand add your component to the map:import TestimonialCard from '@/components/cms/page/testimonial-card';const components: Record<string, ComponentType<any>> = {// ... existing componentsTestimonialCard,};The key (
TestimonialCard) must exactly match theapi_idset in step 1. -
Use it in the CMS
Open any page in Alokai CMS, click + Add in a zone, and select Testimonial Card from the component picker. Fill in the fields and publish.
Passing nested components
If your component contains other components (e.g. a CardGrid that holds multiple Card items), use a components field type in the content model and accept a ReactNode prop in the React component — RenderCmsContent will recursively render children automatically.
// In render-cms-content.tsx, nested `components` fields are resolved// to rendered React elements before being passed as props.
export default function CardGrid({ components, columns = 3, className }: CardGridProps) { return ( <div className={`grid grid-cols-${columns} gap-4 ${className}`}> {components} </div> );}Using the CLI
Content models and content entries can also be created and seeded programmatically. See the CLI reference for details.
Tips
- PascalCase —
api_idmust be PascalCase and match the key in the component map exactly. - Optional fields — make all non-required props optional in TypeScript (
prop?: Type) so the component doesn’t break when fields are left empty by editors. - Images — image fields are passed as
{ url: string; alt: string; width?: number; height?: number }. - Richtext — richtext fields contain an HTML string. Use
dangerouslySetInnerHTMLor a sanitising renderer.