<ui-code>

ui-code.mjs

Accessibility (WCAG)

API

ElementAttributesPropertiesMethodsEvents
<ui-code> src, for, into, lang — — —

1. Inline content

Use this when the snippet is short, page-local, and you want it written right at the call site.

Place code directly between the tags. Excess leading whitespace is stripped at runtime (dedent) — the source you write keeps its indentation.

Show code

2. for + lang="html"

Use this when you want to display the markup of another element on the page — typically the markup of a live demo elsewhere in the doc.

Extract HTML from another element by id. <script> tags are filtered out, so the script body below appears as a separate lang="js" reveal.

Serializing live DOM writes every boolean attribute out as attr="". Recognized boolean attributes — the HTML ones plus this project's own raw, dialog-dismiss and dialog-confirm — are displayed without values, so the shown markup reads the way you would write it.

Picking a target for for=

for= reads the live DOM at extraction time, not the source markup, so the target must hold its original content unchanged. Three patterns, in order of preference:

  1. Plain element ref — a <div id="…"> with static HTML, no nested custom elements that rewrite their own DOM on connect, no inline <script> that mutates at parse. The simplest case; use it when the source remains unchanged.
  2. <template> — when the source contains anything that does mutate live DOM (a nested <ui-code>, another custom element, a parse-time script). Template children are parsed but not connected — no connectedCallback, no script execution — so the markup is preserved verbatim. Pair for= with into= (see section 6) to clone the template into a live container — the same ui-code element does both: shows the template's HTML as code AND renders it into the demo target. Both demos below use this pattern.
  3. src= from a separate file — bypasses for= entirely. See demo 4.

Pointing for= at a container that mutates after parse renders the post-mutation state, which is usually surprising. The doc page demos below all wrap their source in a <template> because every demo container holds a nested <ui-code> — which changes its DOM.

Show code

3. for + lang="js"

Use this when you want to display the JavaScript of a live demo without the surrounding markup.

Extract only the body of <script> tags from the target. Other markup is ignored. The same target-picking rules as the previous section apply — the demo here uses a <template> for the same reason (the source contains a nested <ui-code>).

Show code

4. src attribute

Use this when the snippet is too long to read comfortably inline, reused across pages, or executed by a sibling <script src="…"> so the doc and the live behavior share a single source of truth.

Loads the file via fetch and renders its contents.

Show code

5. Language badge

Use this when several code snippets sit near each other and you want the language clear at a glance.

The lang attribute displays a badge in the upper-left corner. js renders as "JS"; everything else uppercased verbatim. The badge is aria-hidden so screen readers don't double-announce.

Show code

6. into attribute

Use this when a single <template> should drive both the live demo and the shown source — no page-level cloning script.

into= takes the id of a target element. The ui-code resolves for= to a <template>, displays its HTML as code, and clones template.content into the target — recreating <script> nodes so they execute (cloned scripts don't auto-run). Every demo on this page uses this built-in behavior.

Required: for= must point at a <template>. With no for= at all, into= has no effect. Every other failure warns on the console and skips the clone: a for= id that resolves to nothing, a for= that resolves to something other than a <template>, and an into= id that does not identify an element.

Attach demo handlers at the right time

Cloning is synchronous, but the custom element may not yet be registered: a page-level <script type="module"> and ui-code.mjs are separate entries in the module graph, and their execution order is not guaranteed. The page module may run before the demo target is populated, causing intermittent failures. A page-level script that does document.getElementById('my-demo').querySelector('button') gets null, and null.onclick = … throws at module top level — preventing the remaining statements in that module from running. One empty target can therefore disable all demos on the page. A null check avoids the exception but still leaves the demo without a handler.

Use either of these approaches to avoid the timing problem:

Example:

<template id="my-tpl"> <button class="btn">Click</button> <script>/* wires up handler */</script> </template> <div class="demo" id="my-demo"></div> <details> <summary>Show code</summary> <ui-code for="my-tpl" into="my-demo" lang="html"></ui-code> </details>