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.
^[a-z][a-z0-9-]*$ - start with a lowercase letter, then lowercase
letters, digits and hyphens.counter, copy-button, price-tag-2. Invalid:
Counter, 1counter, my_component, ../etc/passwd.<dm-name> and is permanent -
it can't be changed after creation. To rename, create a new component and delete the old one.<template>, <props> and <script> are
required. A missing one fails with MISSING_BLOCK.<style> is optional and defaults to empty.<props> body must be valid JSON and an object (not an
array, not a bare value) - otherwise INVALID_PROPS_JSON.type that is one of string,
number, boolean, array, object. Anything else
(or a missing type) fails validation.default and label are optional. label only affects the
editor's preview panel.export default an object<script> body must be exactly one export default { … };
statement - the compiler strips that prefix and embeds the object. No export default
means SCRIPT_MISSING_EXPORT.export default {}; is valid for a purely presentational component.data() can't see props. It's called with no this
binding, so this.props is unavailable there. Initialise prop-derived state inside
onMount() (which is bound) using this.set(...).
"true"; showReset="false" is still a non-empty
string and coerces to true. To switch a boolean off, set it to "true" or
omit the attribute entirely.
kebab-case attributes - showReset becomes show-reset. The
[component] shortcode accepts the prop name as written.
items='["a","b"]' - and the runtime parses them to the declared type.
this.el.shadowRoot. Attach delegated listeners there (one listener, switch on
data-action) rather than to document.
onUnmount(). Anything you start in onMount
- intervals, timeouts, external listeners - must be torn down in onUnmount so it
doesn't leak when the element is removed.
PLUGIN_OWNED).format no newer than the CMS supports, plus
name and source strings - otherwise INVALID_BUNDLE.CONFLICT unless you confirm the overwrite
(the Import button prompts you).{{ }} interpolation is HTML-escaped, so prop values can't inject markup.dm-* tags, refreshed whenever you
save or delete a component - a component you just created is immediately usable in page content.
on* handler attributes and javascript: URLs are still stripped globally.| 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