Domma CMS User Manual
Text size
Font
Line spacing
Margins
Theme
Layout
Contents
- Domma CMS User Manual
- 1. Using the CMS
- 2. Tutorials
- 3. Components
- 4. API Reference
- 5. Tools
Components Rules
Updated by Darryl Waterhouse on 29 September 2026 · 3 min read
The constraints the compiler enforces, and the handful of behaviours that commonly trip people up. Everything here is validated at save time - a component that breaks a rule never reaches disk.
Naming
- Names must match
^[a-z][a-z0-9-]*$- start with a lowercase letter, then lowercase letters, digits and hyphens. - Valid:
counter,copy-button,price-tag-2. Invalid:Counter,1counter,my_component,../etc/passwd. - The name becomes the element tag
<dm-name>and is permanent - it can't be changed after creation. To rename, create a new component and delete the old one.
Required blocks
<template>,<props>and<script>are required. A missing one fails withMISSING_BLOCK.<style>is optional and defaults to empty.- Blocks are matched by their tags and may appear in any order.
Props must be a typed JSON object
- The
<props>body must be valid JSON and an object (not an array, not a bare value) - otherwiseINVALID_PROPS_JSON. - Every prop must declare a
typethat is one ofstring,number,boolean,array,object. Anything else (or a missing type) fails validation. defaultandlabelare optional.labelonly affects the editor's preview panel.
The script must export default an object
- The
<script>body must be exactly oneexport default { … };statement - the compiler strips that prefix and embeds the object. Noexport defaultmeansSCRIPT_MISSING_EXPORT. - Use an object expression - not a class, not multiple exports. An empty
export default {};is valid for a purely presentational component.
Gotchas worth memorising
1.data()can't see props. It's called with nothisbinding, sothis.propsis unavailable there. Initialise prop-derived state insideonMount()(which is bound) usingthis.set(...).
2. Boolean coercion is string-based. Attribute values are strings. A boolean prop is false only for the string"false"(or when the attribute is left out and the default is false). A bare attribute (show-reset),"true"and any other value, including"no"and"0", coerce totrue. To switch a boolean off, write"false"or omit the attribute.
3. Attribute casing. On the raw custom element, camelCase props are written askebab-caseattributes -showResetbecomesshow-reset. The[component]shortcode accepts the prop name as written.
4. Array / object props are JSON in the attribute. Pass them as a JSON string - e.g. items='["a","b"]' - and the runtime parses them to the declared type.
5. Listen on the shadow root. A component's rendered markup lives inthis.el.shadowRoot. Attach delegated listeners there (one listener, switch ondata-action) rather than todocument.
6. Clean up inonUnmount(). Anything you start inonMount- intervals, timeouts, external listeners - must be torn down inonUnmountso it doesn't leak when the element is removed.
Plugin-owned components are read-only
- Components contributed by a plugin (through
options.hooks.registerComponent({name, source})in itsplugin.js) show a plugin badge, are served from memory, and cannot be edited or deleted from the admin (attempting it returnsPLUGIN_OWNED). - You also can't save a disk component whose name a plugin already owns - pick a different name.
Import / export constraints
- A bundle must have a numeric
formatno newer than the CMS supports, plusnameandsourcestrings - otherwiseINVALID_BUNDLE. - Importing over an existing name returns
CONFLICTunless you confirm the overwrite (the Import button prompts you). - Imported source is compiled like any save, so a broken bundle is rejected with the same errors.
Rendering & safety notes
{{ }}interpolation is HTML-escaped, so prop values can't inject markup.- The markdown sanitiser keeps a live allowlist of
dm-*tags, refreshed whenever you save or delete a component - a component you just created is immediately usable in page content.on*handler attributes andjavascript:URLs are still stripped globally. - Saving recompiles and invalidates the cached module, so edits take effect on the next page load without a server restart.
Compiler error codes at a glance
| Code | Meaning |
|---|---|
INVALID_NAME | Name doesn't match the naming rule. |
MISSING_BLOCK | A required <template> / <props> / <script> block is absent. |
INVALID_PROPS_JSON | Props aren't a JSON object, or a prop has an invalid/missing type. |
SCRIPT_MISSING_EXPORT | The script has no export default object. |
PLUGIN_OWNED | Tried to edit/delete (or shadow) a plugin-contributed component. |
INVALID_BUNDLE / CONFLICT | Import bundle malformed, or a name collision needs overwrite confirmation. |
Back to Reference · How-To · Walkthrough
Back where you left off.