Contents

Props and names

You already registered booking-form and dropped Custom on Maya's homepage hero. This page is the rest of the menu: the prop types she can author, keys RuleCMS drops, the name grammar, what a miss looks like, and why the HTML embed can never show her form. If you are still looking for the first walkthrough, go back to Mount Your Own Components.

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 typeStored asHer component receivesDropped when
Textstringthe string as typednever, if the row is well-formed
Numbernumbera finite numberthe value is not a finite number (twelve, blank)
Yes / nobooleantrue or falseanything other than the exact strings true / false
JSONjsonthe 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-style onX, plus a set of HTML events such as onclick and onload
  • 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

SurfaceWhat renders
Composer canvasAlways the dashed placeholder. RuleCMS never receives mounts.
Her app, name matches a keyHer component, inside the column box.
Her app, name missing or misspelledThe placeholder, showing the name they typed. Outside production, the console warns once and lists the keys you registered.
Her app, you passed no mountsThe placeholder. Publishing does not invent a registration.
HTML script embedAlways 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

QuestionAnswer
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

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.