Mixin Types
π Table of Contents
Overview
Mixin types allow a SmarkForm component to be defined by an HTML <template> element rather than by a fixed native type such as form, list, or input. They give authors a lightweight way to create reusable component βblueprintsβ that can be stamped out anywhere in a form tree β and even loaded from external files β without writing any JavaScript.
A mixin type is identified by a mixin type reference: a string that starts with # (local template) or contains # (external URL + template id):
| Reference | Meaning |
|---|---|
"#myWidget" | Template with id="myWidget" in the current document |
"./widgets.html#myWidget" | Template with id="myWidget" in external file widgets.html |
"https://cdn.example.com/sf-widgets.html#myWidget" | Absolute URL + template id |
Whenever SmarkForm sees a type value that is a mixin reference it:
- Locates the referenced
<template>element (locally or via fetch). - Clones the templateβs single root element.
- Merges attributes and
data-smarkoptions from the placeholder node into the clone. - Replaces the placeholder node with the clone in the DOM.
- Continues enhancement as if the clone had been there from the start.
Defining a Mixin Template
A mixin is declared with a plain HTML <template> element that has an id:
<template id="myWidget">
<div data-smark='{"type":"form"}'>
<input data-smark='{"name":"value"}' type="text">
</div>
</template>
The <template> element itself requires no data-smark attribute; its purpose is solely to hold the blueprint markup.
Place
<template>elements at document level (e.g., directly inside<body>, or in<head>when the browser allows it) β not as direct children of a SmarkFormlistcontainer. See the List Placement Warning section.
Using a Mixin Type
Local mixin reference
Reference a template in the same document by its id, prefixed with #:
<!-- Declare the mixin template once -->
<template id="labeledInput">
<label data-smark>
<span class="label-text"></span>
<input type="text">
</label>
</template>
<!-- Use the mixin type anywhere in the form -->
<form id='myForm'>
<div data-smark='{"type":"#labeledInput","name":"firstName"}'></div>
<div data-smark='{"type":"#labeledInput","name":"lastName"}'></div>
</form>
External mixin reference
Reference a template in an external HTML file using a relative or absolute URL followed by #<templateId>:
<form id='myForm'>
<!-- Load template from a shared widget library -->
<div data-smark='{"type":"./shared/widgets.html#phoneField","name":"phone"}'></div>
<div data-smark='{"type":"./shared/widgets.html#emailField","name":"email"}'></div>
</form>
The external file shared/widgets.html would contain:
<!DOCTYPE html>
<html>
<body>
<template id="phoneField">
<label data-smark>
<span>Phone</span>
<input type="tel" data-smark='{"name":"number"}'>
</label>
</template>
<template id="emailField">
<label data-smark>
<span>E-mail</span>
<input type="email" data-smark='{"name":"address"}'>
</label>
</template>
</body>
</html>
External URLs are resolved against
document.baseURI(for relative paths). The same external document is fetched only once per page load and its templates are cached for all subsequent references.
Template Constraints
The referenced <template> must satisfy the following constraints; otherwise SmarkForm raises a normative error (see Error Codes):
| Constraint | Rationale |
|---|---|
The <template> element must exist and its id must match the fragment | Without it there is nothing to clone |
| The template must contain exactly one root element node | SmarkForm replaces the placeholder with a single node; extra text or comment nodes are ignored, but extra element nodes are an error |
<style> and <script> siblings of the root are allowed and do not count toward the one-element limit | They carry component styles/behaviour, not markup |
The template root element must not specify a name inside its data-smark options | The name belongs to the placeholder (the usage site), not the blueprint |
<!-- β
Valid: single root, no name -->
<template id="myField">
<div data-smark='{"type":"form"}'> ... </div>
</template>
<!-- β
Valid: root may omit data-smark entirely -->
<template id="simpleWidget">
<div class="widget"> ... </div>
</template>
<!-- β
Valid: <style> and <script> siblings are allowed alongside the root -->
<template id="styledWidget">
<div data-smark='{"type":"form"}'> ... </div>
<style>.widget { border: 1px solid #ccc; }</style>
<script>this.targetNode.classList.add('widget');</script>
</template>
<!-- β Invalid: two root elements -->
<template id="broken">
<div>first</div>
<div>second</div>
</template>
<!-- β Invalid: root has "name" in data-smark -->
<template id="namedRoot">
<div data-smark='{"name":"hardcoded"}'> ... </div>
</template>
Expansion Semantics
Mixin expansion is a preprocessing step that happens during SmarkFormβs component discovery/enhancement pass, before the replaced node is itself enhanced. From the perspective of the rest of the rendering pipeline the mixin placeholder never existed; only its expanded form is visible.
The sequence is:
- SmarkForm encounters a node whose
data-smark.typeis a mixin reference. - SmarkForm resolves and fetches (if external) the referenced template.
- The templateβs single root element is cloned (deep clone).
- Attributes and options are merged (see the next two sections).
- The placeholder node is replaced in the DOM with the merged clone.
- Enhancement continues on the clone as if it were the original node.
Future option (not in v1): A
"placement"option could allow"nest"(wrap placeholder inside the clone) in addition to the default"replace". v1 only supports"replace".
Option Merge Semantics
The placeholderβs data-smark options are merged with the template rootβs data-smark options before enhancement begins. The merge rules are:
| Option key | Rule |
|---|---|
name | Taken from the placeholder (placeholder value wins; template root must not set it) |
type | The mixin reference is consumed during expansion and does not become the final type; the cloneβs own type (if any) is used as the concrete component type |
| All other keys | Placeholder value overrides template root value (template provides defaults, placeholder overrides) |
<!-- Template defines default options -->
<template id="countrySelect">
<select data-smark='{"type":"select","exportEmpty":false}'></select>
</template>
<!-- Placeholder overrides exportEmpty; name comes from placeholder -->
<div data-smark='{"type":"#countrySelect","name":"country","exportEmpty":true}'></div>
After expansion the effective options are:
{ "type": "select", "name": "country", "exportEmpty": true }
Attribute Merge Semantics
When the placeholder is replaced by the template root clone, HTML attributes are merged according to the following rules:
| Attribute | Merge rule |
|---|---|
class | Union β template classes and placeholder classes are both preserved |
style | Concatenation β template style first, then placeholder style, separated by ;; the placeholder can therefore override any template property |
aria-* | Template value is the default; placeholder value overrides if present |
data-* (except data-smark) | Template value is the default; placeholder value overrides if present |
id | Not copied/merged; if the placeholder carries an id it is ignored (with a warning) because SmarkForm may later assign auto-generated ids |
| All other attributes | Non-conflicting attributes are copied from the placeholder to the clone; where both define the same attribute, the placeholder wins |
<!-- Template root -->
<template id="fancyInput">
<input data-smark class="form-control" style="border: 1px solid #ccc;" aria-required="false">
</template>
<!-- Usage site -->
<div
data-smark='{"type":"#fancyInput","name":"email"}'
class="email-field"
style="color: red;"
aria-required="true"
></div>
After expansion the effective element is:
<input
data-smark='{"name":"email"}'
class="form-control email-field"
style="border: 1px solid #ccc;color: red;"
aria-required="true"
>
Snippet Parameters
Snippet parameters let you customise the internals of a mixin at each usage site by supplying replacement elements as children of the placeholder node. Each replacement child must carry a data-for attribute that names the element inside the template it should replace.
This is a purely DOM-level substitution β no template engine, no string interpolation. The supplied element (including its tag name, attributes, and all descendants) replaces the template element entirely, giving you the full power to redefine any part of the template.
How snippet parameters work
- Mark replaceable slots inside the mixin template by giving them an
id. - Supply the replacement as a direct child of the placeholder, with a matching
data-for="<id>"attribute. - SmarkForm swaps out the template element before rendering begins β the original element is gone and the replacement takes its place.
- The
data-forchild is consumed: it never appears in the final DOM as a child of the placeholder.
<!-- Template declares a slot via id="labelText" -->
<template id="labeledInput">
<label data-smark>
<span id="labelText">Default label</span>
<input type="text">
</label>
</template>
<!-- Usage site supplies a replacement for that slot -->
<div data-smark='{"type":"#labeledInput","name":"email"}'>
<span data-for="labelText">E-mail address</span>
</div>
<!-- Another usage site with a different label -->
<div data-smark='{"type":"#labeledInput","name":"phone"}'>
<span data-for="labelText">Phone number</span>
</div>
Each instance gets its own independent content β the template is cloned fresh for every expansion.
If the
data-forvalue does not match any elementidin the template, the parameter is silently ignored and the template default remains in place.
id β data-id conversion
After snippet substitutions have been applied, SmarkForm converts every remaining id attribute in the cloned subtree to a data-id attribute. This means:
- Surviving template slots (those not replaced by a
data-forchild) become self-documenting: you can inspectdata-idto discover which ids are available for parameterisation. - id attributes on inserted parameter nodes are also converted (using an
idinside a mixin is considered bad practice). - The mixin can be used multiple times on the same page without ever introducing duplicate
idattributes.
<!-- Before expansion: template has two slots -->
<template id="twoSlots">
<div data-smark='{"type":"form"}'>
<span id="title">Default title</span>
<p id="description">Default description</p>
</div>
</template>
<!-- Usage: override only the title -->
<div data-smark='{"type":"#twoSlots","name":"section"}'>
<span data-for="title">Custom title</span>
</div>
<!--
After expansion the rendered subtree looks like:
<div data-smark='{"type":"form","name":"section"}'>
<span>Custom title</span> β replaced, no id/data-id
<p data-id="description">Default description</p> β surviving, data-id
</div>
-->
Because ids inside mixin templates are always removed before rendering, mixin styles should use CSS classes to target elements β never ids. SmarkForm automatically handles label/field association internally.
Security: no nested scripts
SmarkForm disallows <script> elements anywhere inside the template root subtree (i.e., nested within the root element and its descendants). Attempting to place a <script> there throws a MIXIN_NESTED_SCRIPT_DISALLOWED error.
<script> elements are only supported as direct siblings of the root element β the top-level position inside the <template> tag β where they are extracted and run as per-instance behaviour (see Scripts).
This restriction also applies to any elements injected via data-for: if a replacement element contains a nested <script>, the error is thrown before any enhancement takes place.
External Loading and Caching
URL resolution
A mixin type reference must contain a #<templateId> fragment. A reference without a fragment causes a MIXIN_TYPE_MISSING_FRAGMENT error.
- Local reference (
"#<templateId>"): the template is looked up byidindocument. - External reference (
"<url>#<templateId>"): the URL part (everything before#) is resolved againstdocument.baseURIusing the standardURLconstructor.
Fetch and cache strategy
External documents are fetched once per page load. The recommended internal cache is:
Map<absoluteUrlWithoutFragment, Promise<Document>>
On first access SmarkForm initiates a fetch(), parses the response as HTML, and stores the resulting Promise<Document> in the map. All subsequent requests for the same URL (even with different fragment ids) reuse the same cached promise, so only one network request is ever made per external document.
The expansion stack (used for circular dependency detection) uses a different, more specific key format: absoluteUrl#templateId. This distinction is intentional β the document cache is keyed by URL alone because one fetch retrieves all templates from that document, while the expansion stack is keyed per template to catch cycles at the individual template level.
Nested mixins and circular dependency detection
A mixin template may itself reference another mixin type (nested mixins). To prevent infinite expansion, SmarkForm maintains an expansion stack of keys of the form absoluteUrl#templateId (local references use document.baseURI as their URL). Before expanding any mixin SmarkForm checks whether the key is already present in the stack. If it is, a MIXIN_CIRCULAR_DEPENDENCY error is thrown.
List Placement Warning
Do not place
<template>nodes as direct children of a SmarkFormlistcontainer.A
listcomponent treats every direct child as a role template (such asitem,empty-list,add-item, etc.) and removes those children from the DOM during initialisation. A<template>element placed there will be silently consumed and will never be available for mixin expansion.Recommendation: Define mixin templates outside any SmarkForm list, for example at the top level of
<body>, inside<head>(where browsers permit), or in a dedicated<div>that is itself not managed by SmarkForm.
<!-- β
Safe: template defined at document level -->
<template id="phoneEntry">
<div data-smark='{"type":"form"}'>
<input data-smark='{"name":"number"}' type="tel">
</div>
</template>
<form data-smark='{"id":"contacts"}'>
<ul data-smark='{"name":"phones"}'>
<!-- β
The mixin type is referenced from inside the list item template,
not defined here. -->
<li data-smark='{"role":"item"}'>
<div data-smark='{"type":"#phoneEntry","name":"phone"}'></div>
</li>
</ul>
</form>
<!-- β Antipattern: template as direct child of list -->
<ul data-smark='{"name":"phones"}'>
<template id="phoneEntry"> ... </template> <!-- consumed by list! -->
<li data-smark='{"role":"item"}'> ... </li>
</ul>
Scripts and Styles
<style> and <script> elements can be placed as siblings of the root element inside a <template>, giving mixin authors a way to bundle component-specific styles and behaviour alongside their markup.
This feature is exclusive to mixin templates. Placing
<style>or<script>directly inside a regular page element (outside a<template>) causes the browser to parse and execute them immediately at page load, making deferred/per-instance execution impossible. The<template>tag prevents that and is therefore the only supported location.
A mixin template may contain up to three direct children:
- One root element (the component markup β required)
- One
<style>element (component styles β optional) - One
<script>element (component behaviour β optional)
<template id="myWidget">
<div data-smark='{"type":"form"}'>
<!-- component markup -->
<input data-smark type="text" name="value">
</div>
<style>
/* Component-specific styles */
.widget-root { border: 1px solid #ccc; }
</style>
<script>
// Component-specific behaviour (`this` = SmarkForm component instance)
this.targetNode.classList.add('widget-root');
</script>
</template>
Styles
A <style> element that is a direct sibling of the template root element is extracted and injected into <head> exactly once per unique content. Injecting the same style block from multiple mixin instances is safe β the deduplication ensures the <style> appears in <head> only once, regardless of how many times the mixin is used.
Injected styles are global. Authors are responsible for using specific selectors to avoid conflicts between different mixin types. Future versions may introduce scoped styles via a convention-based wrapper selector.
Scripts
A <script> element that is a direct sibling of the template root element is extracted, wrapped into a function, and executed once per component instance after the component has finished rendering. The function receives this bound to the SmarkForm component instance, enabling direct API access.
<template id="autoFocus">
<input data-smark type="text">
<script>
// `this` is the SmarkForm component instance
this.on("AfterAction_import", (ev) => {
console.log("Form loaded with:", ev.data);
});
</script>
</template>
Scripts run per instance. If a list clones a mixin that contains a
<script>, the script runs for every list item that uses that mixin. Ensure handlers are idempotent or clean up onunrenderto avoid memory leaks.
Mixin Security Options
SmarkForm uses a secure-by-default model: all mixin script execution and external template loading is blocked unless explicitly allowed. This prevents unexpected dynamic-code execution or network requests introduced by mixin templates.
Three separate concerns are controlled by root-level options on the SmarkForm instance (or any ancestor component via inheritedOption):
1. External template fetch policy β allowExternalMixins
Controls whether SmarkForm is permitted to fetch templates from external URLs (any mixin type that contains a URL part before the # fragment).
| Value | Behaviour |
|---|---|
"block" (default) | Any attempt to load an external mixin template throws MIXIN_EXTERNAL_FETCH_BLOCKED and halts rendering. |
"same-origin" | Only same-origin URLs are permitted; cross-origin URLs throw MIXIN_CROSS_ORIGIN_FETCH_BLOCKED. |
"allow" | External templates may be loaded from any origin. |
// Allow loading templates from the same server only
new SmarkForm(el, { allowExternalMixins: 'same-origin' });
2. Script execution policy β allowLocalMixinScripts, allowSameOriginMixinScripts, allowCrossOriginMixinScripts
Controls whether <script> elements found at the top level of a <template> are executed after the component renders. The applicable option is determined by where the template was loaded from:
| Template origin | Controlling option |
|---|---|
Local (#id only, no URL) | allowLocalMixinScripts |
| External, same origin | allowSameOriginMixinScripts |
| External, cross-origin | allowCrossOriginMixinScripts |
Each option accepts the same three values:
| Value | Behaviour |
|---|---|
"block" (default) | A template <script> throws a script-blocked error and halts rendering. Fail loudly so the developer makes an explicit decision. |
"noscript" | The template renders normally but its <script> is silently discarded. Useful when you trust the template markup but not its scripts. |
"allow" | Scripts are executed as normal. |
// Allow local mixin scripts only
new SmarkForm(el, { allowLocalMixinScripts: 'allow' });
// Allow loading and executing scripts from same-origin external templates
new SmarkForm(el, {
allowExternalMixins: 'same-origin',
allowSameOriginMixinScripts: 'allow',
});
Setting
allowCrossOriginMixinScriptsto"allow"grants full script execution for templates loaded from third-party origins. Only use this when you fully control and trust those external sources.
Examples
Reusable contact block
The following example defines a single #contactBlock mixin template and stamps it out twice β once for the primary contact and once for an emergency contact. Both instances share the same structure but are completely independent, each carrying its own name and therefore its own data path in the exported value.
<div id="myForm">
<!-- Form β the same mixin is used for both contacts -->
<fieldset data-smark='{"type":"form","name":"contacts"}'>
<legend>Contacts</legend>
<h3>Primary</h3>
<div data-smark='{"type":"#contactBlock","name":"primary"}'></div>
<h3>Emergency</h3>
<div data-smark='{"type":"#contactBlock","name":"emergency"}'></div>
</fieldset>
</div>
<!-- Mixin template β defined once, reused anywhere -->
<template id="contactBlock">
<fieldset data-smark='{"type":"form"}'>
<label data-smark>
Name: <input data-smark type="text" name="name">
</label>
<label data-smark>
E-mail: <input data-smark type="email" name="email">
</label>
<label data-smark>
Phone: <input data-smark type="tel" name="phone">
</label>
</fieldset>
</template>
const myForm = new SmarkForm(document.getElementById("myForm"), {
"value": {
"contacts": {
"primary": {
"name": "Alice Smith",
"email": "alice@example.com",
"phone": "555-1234"
},
"emergency": {
"name": "Bob Smith",
"email": "bob@example.com",
"phone": "555-5678"
}
}
}
});
Every example in this section comes with many of the following tabs:
- HTML: HTML source code of the example.
- CSS: CSS applied (if any).
- JS: JavaScript source code of the example.
- Preview: Live, sandboxed rendering of the example β fully isolated from the page styles.
- Notes: Additional notes and insights for better understanding. Don't miss itβΌοΈ
β¨ In the Preview tab, a JSON playground editor is available with handy buttons:
β¬οΈ Exportto export the form data to the JSON playground editor.β¬οΈ Importto import data from the JSON playground editor into the form.β»οΈ Resetto reset the form to its default values.β Clearto clear the whole form.
π‘ The JSON playground editor is part of the SmarkForm form itself β it is just omitted from the code snippets to keep the examples focused on what matters.
π οΈ Between the tab labels and the content there is always an edit toolbar:
βοΈ Editβ activates edit mode: each source tab turns into a syntax-highlighted code editor (powered by Ace) pre-filled with the full, merged source. Changes are sandboxed β the original example is not affected.π Include playground editorβ (only visible in edit mode) controls whether the JSON playground editor is included in the preview. When toggled, the HTML and JS editors update instantly so you can see exactly what code is needed to add or remove it.βΆοΈ Runβ (only visible in edit mode) re-renders the Preview from the current editor contents and switches to the Preview tab.
The exported value mirrors the nesting: both primary and emergency objects appear under a contacts key, each with name, email, and phone fields β exactly what you would get from two independently hand-authored <fieldset> blocks, but with zero markup duplication.
Option override per usage site
Placeholder options override template defaults on a per-key basis. The following example uses a single #tagList template that declares "min_items":3 as its default. One of the two usage sites overrides that to "min_items":1 so it starts with only one slot, while the other keeps the templateβs default of three.
<div id="myForm">
<fieldset data-smark='{"type":"form","name":"labels"}'>
<legend>Labels</legend>
<h3>Priority tags (3 slots by default)</h3>
<!-- No min_items override β keeps template default of 3 -->
<div data-smark='{"type":"#tagList","name":"priority"}'></div>
<button data-smark='{"action":"addItem","context":"priority"}'>β Add</button>
<h3>Optional tags (1 slot override)</h3>
<!-- Overrides min_items to 1 -->
<div data-smark='{"type":"#tagList","name":"optional","min_items":1}'></div>
<button data-smark='{"action":"addItem","context":"optional"}'>β Add</button>
</fieldset>
</div>
<template id="tagList">
<!-- Template default: start with 3 items -->
<ul data-smark='{"type":"list","min_items":3}'>
<li>
<input data-smark type="text" name="tag" placeholder="tagβ¦">
<button data-smark='{"action":"removeItem"}'>β</button>
</li>
</ul>
</template>
const myForm = new SmarkForm(document.getElementById("myForm"), {
"value": {"labels":{"priority":[{"tag":"critical"},{"tag":"needs-review"},{"tag":"assigned"}],"optional":[{"tag":"nice-to-have"}]}}
});
Every example in this section comes with many of the following tabs:
- HTML: HTML source code of the example.
- CSS: CSS applied (if any).
- JS: JavaScript source code of the example.
- Preview: Live, sandboxed rendering of the example β fully isolated from the page styles.
- Notes: Additional notes and insights for better understanding. Don't miss itβΌοΈ
β¨ In the Preview tab, a JSON playground editor is available with handy buttons:
β¬οΈ Exportto export the form data to the JSON playground editor.β¬οΈ Importto import data from the JSON playground editor into the form.β»οΈ Resetto reset the form to its default values.β Clearto clear the whole form.
π‘ The JSON playground editor is part of the SmarkForm form itself β it is just omitted from the code snippets to keep the examples focused on what matters.
π οΈ Between the tab labels and the content there is always an edit toolbar:
βοΈ Editβ activates edit mode: each source tab turns into a syntax-highlighted code editor (powered by Ace) pre-filled with the full, merged source. Changes are sandboxed β the original example is not affected.π Include playground editorβ (only visible in edit mode) controls whether the JSON playground editor is included in the preview. When toggled, the HTML and JS editors update instantly so you can see exactly what code is needed to add or remove it.βΆοΈ Runβ (only visible in edit mode) re-renders the Preview from the current editor contents and switches to the Preview tab.
Notice how both priority and optional use the same #tagList blueprint, but each instance gets its own initial item count controlled by the min_items option β set by the placeholder for optional and falling through to the template default for priority.
Snippet parameters β custom labels
The following example shows a #personEntry mixin where each usage site customises the label of the name field via a snippet parameter. The template uses id="nameLabel" to mark the slot, and each placeholder supplies its own <span data-for="nameLabel"> replacement.
<div id="myForm">
<fieldset data-smark='{"type":"form","name":"people"}'>
<legend>People</legend>
<div data-smark='{"type":"#personEntry","name":"author"}'>
<span data-for="nameLabel">Author name</span>
</div>
<div data-smark='{"type":"#personEntry","name":"reviewer"}'>
<span data-for="nameLabel">Reviewer name</span>
</div>
</fieldset>
</div>
<!-- Mixin template β nameLabel slot is the default text for the label -->
<template id="personEntry">
<fieldset data-smark='{"type":"form"}'>
<label>
<span id="nameLabel">Name</span>
<input data-smark type="text" name="name">
</label>
</fieldset>
</template>
const myForm = new SmarkForm(document.getElementById("myForm"), {
"value": {"people":{"author":{"name":"Alice Smith"},"reviewer":{"name":"Bob Jones"}}}
});
Every example in this section comes with many of the following tabs:
- HTML: HTML source code of the example.
- CSS: CSS applied (if any).
- JS: JavaScript source code of the example.
- Preview: Live, sandboxed rendering of the example β fully isolated from the page styles.
- Notes: Additional notes and insights for better understanding. Don't miss itβΌοΈ
β¨ In the Preview tab, a JSON playground editor is available with handy buttons:
β¬οΈ Exportto export the form data to the JSON playground editor.β¬οΈ Importto import data from the JSON playground editor into the form.β»οΈ Resetto reset the form to its default values.β Clearto clear the whole form.
π‘ The JSON playground editor is part of the SmarkForm form itself β it is just omitted from the code snippets to keep the examples focused on what matters.
π οΈ Between the tab labels and the content there is always an edit toolbar:
βοΈ Editβ activates edit mode: each source tab turns into a syntax-highlighted code editor (powered by Ace) pre-filled with the full, merged source. Changes are sandboxed β the original example is not affected.π Include playground editorβ (only visible in edit mode) controls whether the JSON playground editor is included in the preview. When toggled, the HTML and JS editors update instantly so you can see exactly what code is needed to add or remove it.βΆοΈ Runβ (only visible in edit mode) re-renders the Preview from the current editor contents and switches to the Preview tab.
Each placeholder supplies its own label text; the template default ("Name") would appear on any instance that does not provide a data-for="nameLabel" child. After expansion there are no id attributes in the rendered DOM β the slot is self-documented via data-id="nameLabel" on surviving nodes.
Error Codes
The following normative error codes are defined for the mixin types feature. Implementations must use these identifiers so that application code can distinguish error causes programmatically.
| Error code | When thrown |
|---|---|
MIXIN_TYPE_MISSING_FRAGMENT | The mixin type reference does not contain a #<templateId> fragment |
MIXIN_EXTERNAL_FETCH_BLOCKED | The mixin type references an external URL but allowExternalMixins is "block" (the default) |
MIXIN_CROSS_ORIGIN_FETCH_BLOCKED | The mixin type references a cross-origin URL but allowExternalMixins is "same-origin" |
MIXIN_TEMPLATE_NOT_FOUND | No <template> element with the given id exists in the target document |
MIXIN_TEMPLATE_INVALID_ROOT | The template does not contain exactly one root element node |
MIXIN_TEMPLATE_ROOT_HAS_NAME | The template root elementβs data-smark options specify a name |
MIXIN_CIRCULAR_DEPENDENCY | The expansion stack already contains the current mixin key (infinite loop detected) |
MIXIN_SCRIPT_LOCAL_BLOCKED | A local mixin template contains a <script> and allowLocalMixinScripts is "block" (the default) |
MIXIN_SCRIPT_SAME_ORIGIN_BLOCKED | A same-origin external mixin template contains a <script> and allowSameOriginMixinScripts is "block" (the default) |
MIXIN_SCRIPT_CROSS_ORIGIN_BLOCKED | A cross-origin mixin template contains a <script> and allowCrossOriginMixinScripts is "block" (the default) |
MIXIN_NESTED_SCRIPT_DISALLOWED | A <script> element was found inside the template root subtree (nested scripts are not allowed; use top-level sibling <script> inside the <template> instead) |