The rest of the menu
You already registered booking-form and dropped Custom on Maya's homepage hero from Mount Your Own Components. This page is the rest of the menu: the prop types she can author, the keys RuleCMS drops, the name grammar, what a miss looks like, and why the HTML embed can never show her form.
Keep that form in mind. She types variant as Text and seats as Number. You pass onBooked from the app. A typo in the name is still a dashed box.
The walkthrough — write the component, register mounts, give her the name, drop Custom, publish and deploy — lives on Mount Your Own Components. This page does not replace that first path.
Prop types she can author
Each row in Props is a name, a type, and a value. RuleCMS coerces the value, then drops the row if it fails. A marketer who picks the wrong type will not break the page. A marketer who adds a name the form does not read will not break it either — unknown props are ignored, the same as an unknown HTML attribute.
| Composer type | Stored as | Her component receives | Dropped when |
|---|---|---|---|
| Text | string | the string as typed | never, if the row is well-formed |
| Number | number | a finite number | the value is not a finite number (twelve, blank) |
| Yes / no | boolean | true or false | anything other than the exact strings true / false |
| JSON | json | the parsed value (object, array, number, …) | JSON.parse throws |
These values are public. They ship in the published widget JSON. Anyone can read them. Do not put tokens or passwords there.
Keys that are never passed
RuleCMS drops these from the authored list, in the editor and at render. They cannot become behaviour.
- Event names: anything matching
onClick-styleonX, plus a set of HTML events such asonclickandonload - React reserved:
key,ref,children - HTML injection:
dangerouslySetInnerHTML - Prototype chain:
__proto__,constructor,prototype
To pass onBooked or onClick, use componentProps addressed at the Custom component's Component id:
<RuleCMSWidget
publishedKey={publishedKey}
mounts={{ 'booking-form': BookingForm }}
componentProps={{
[BOOKING_COLUMN_ID]: { onBooked: openConfirmation },
}}
/>componentProps still cannot go on RuleCMSWidgetServer. Fetch on the server and render from a client component, the same pattern as the Custom Props guide.
The name grammar
The composer and the renderer accept the same pattern: start with a letter, then letters, digits, hyphens, or underscores, up to 64 characters.
booking-form ok booking_form ok BookingForm ok bookingForm ok — and different from booking-form 2fa-form refused (leading digit) booking form refused (space) booking.form refused (dot)
Pick one style and keep it. Hyphenated lowercase is the easiest to read over a Slack message and the hardest to camelCase by accident. booking-form and bookingForm are different keys. A misspelled name is a dashed box.
She can uncheck "Same value for all resolutions" on Component Name and type booking-form-compact for phone, booking-form for desktop. You have to register both names. Two components, one slot.
What you will see, and what they will see
| Surface | What renders |
|---|---|
| Composer canvas | Always the dashed placeholder. RuleCMS never receives mounts. |
| Her app, name matches a key | Her component, inside the column box. |
| Her app, name missing or misspelled | The placeholder, showing the name they typed. Outside production, the console warns once and lists the keys you registered. |
Her app, you passed no mounts | The placeholder. Publishing does not invent a registration. |
| HTML script embed | Always the placeholder. The script does not contain her components and has no way to receive a React component type. |
r-mount: no host component registered as "booking-form". Registered names: pricing-calc.
Production is silent. A visitor is not a developer. The dashed box still shows the name they typed, so a typo is visible on the page.
What her component receives
On a hit, Custom renders a wrapper <div> that carries the column's box styles, then her component:
<div style={columnStyles} className={columnClassName}>
<BookingForm
{...widgetInstanceProps}
variant="compact"
seats={12}
showWaitlist={true}
theme={{ accent: '#0af' }}
/>
</div>Author props are never spread onto the wrapper. Her component is a child, not the box. Size, padding, and hide belong to the column.
widgetInstanceProps (published key, environment, and the rest of the instance bag) are passed first. Author props overwrite on collision. Do not publish a configuration name that clashes with an instance field you still need.
Server-rendered pages
Pass the same map to RuleCMSWidgetServer. Her component is rendered on the server if it can be. Unlike componentProps, this is a component the renderer invokes, so it does not have to cross the Server Component boundary as a function prop of the visitor's. If the form needs hooks or click handlers, mark it 'use client' and register that module.
import { RuleCMSWidgetServer } from '@rulecms/widget-react/server';
import * as sourceComponents from '@rulecms/source-components-react';
import { BookingForm } from './BookingForm';
export default async function Page() {
return (
<RuleCMSWidgetServer
publishedKey={publishedKey}
token={token}
libraries={{ default: sourceComponents }}
mounts={{ 'booking-form': BookingForm }}
/>
);
}The HTML custom-element embed cannot do this. Use @rulecms/widget-react in a React (or Next.js) host. A WordPress page that only loads the script tag will keep showing the dashed box.
Things worth knowing
| Question | Answer |
|---|---|
| Can the composer preview her component? | No. The dashed box is the product. RuleCMS does not have her bundle. |
| Is the name loaded as code? | No. It is mounts[name]. A miss is a placeholder. There is no import(name) and no URL in the widget JSON. |
| Do I have to register the map on every widget on the page? | On every RuleCMSWidget that should be able to resolve those names. A widget you did not pass the map to cannot fill the slot. |
| What if they type a prop I do not read? | Nothing happens. Same as an unknown HTML attribute on a DOM node you do not look at. |
| Can they pass children? | No. Custom is a leaf. Nested cards inside a host component are not shipped. |
| Are prop values secret? | No. They are in the published widget JSON. Anyone can read them. Do not put tokens or passwords there. |
What to read next
- Mount Your Own Components — The Maya-hero walkthrough: write
BookingForm, registermounts, give her the name, drop Custom, publish and deploy. - Custom Component — The marketer's page.
- Component Name and Props — The Modify-drawer settings she fills.
- Custom Props and Click Handlers — Handlers by Component id.
- HTML Custom Element Embed — Cannot receive a component type.
How this fits
This page does not replace the first path. Register booking-form on the hub, then come here when she asks why a Number row did nothing, why onBooked never arrived, or why a WordPress page still shows the box.
Author props configure the form. The column box owns size, padding, and hide. componentProps owns handlers. The three stay separate on purpose.