Lit Element: Reuse a Reference Section in a Deliverable HTML File

Keep each reused reference element independent and deliver the runtime with the page.

Your report has two expandable source notes. Opening the second should not close the first or replace its heading. Define a Lit element once, put it in the document twice and let each instance keep its own state. Then deliver the runtime with the document so the component can actually render.

A custom tag is a place to reuse behavior, not a substitute for the JavaScript that defines it. The original example here is a fictional print-review handout with two complete source excerpts. It does not submit requests, contact a museum or record an actual collection.

Actual Lit runtime: two original fictional reference excerpts with independent controls
Actual Lit runtime: two original fictional reference excerpts with independent controls
Open the full example ↗

Open the complete example · Download the full HTML source

Define the element before relying on its behavior

Lit’s component definition guide describes extending LitElement and registering the class with customElements.define(). The JavaScript form below uses that registration directly, with no decorator syntax:

import {LitElement, html} from './lit.bundle.mjs';

class SourceExcerpt extends LitElement {
  static properties = {
    label: {type: String},
    expanded: {type: Boolean, reflect: true}
  };
  constructor() {
    super();
    this.label = 'Source excerpt';
    this.expanded = false;
  }
  render() {
    return html`
      <section>
        <h2>${this.label}</h2>
        <button type="button"
          aria-expanded=${String(this.expanded)}
          @click=${() => { this.expanded = !this.expanded; }}>
          ${this.expanded ? 'Hide excerpt' : 'Read excerpt'}
        </button>
        <div ?hidden=${!this.expanded}><slot></slot></div>
      </section>`;
  }
}
customElements.define('source-excerpt', SourceExcerpt);

This is the component recipe, not a complete delivery file. The neighboring module must exist, and the page needs its document shell and styles. In the complete download, the selected Lit bundle is carried inside the HTML as an embedded module so the reading copy does not fetch it from a remote service.

Put ordinary source text inside each instance

Use one element for “Collecting a print” and another for “Requesting a correction.” Their excerpt text remains authored HTML inside the element; the component supplies the heading and disclosure behavior around the slot.

<source-excerpt label="Collecting a print" expanded>
  <p>Fictional instruction: compare the print title with the pickup
  note before taking the labeled envelope.</p>
</source-excerpt>
<source-excerpt label="Requesting a correction">
  <p>Fictional instruction: name the wording to change and the
  replacement wording in the coordinator’s actual request channel.</p>
</source-excerpt>

Keep the excerpt separate from its display state. Hiding a section does not withdraw its instruction or prove that the reader followed it. The complete example supplies the rest of each fictional note and leaves the actual coordinator and request route unspecified.

Lit’s reactive-property guide explains that a declared reactive property schedules an update when changed. Here expanded is Boolean and reflected to its attribute. The initial expanded attribute opens only the first instance. A separate label string supplies each heading.

In this Boolean example, expanded="false" still leaves the attribute present and the excerpt open. Remove the attribute or set the expanded property to false when you want it closed.

Test two instances, not one working button

Begin with the collection note open and the correction note closed. Open the correction note: both should now be readable. Close the collection note: the correction note should stay open. Restore the example and check that the initial open/closed arrangement returns.

Also change the second instance’s label property in the maintained source or a deliberate development check. Its heading should update while the first heading remains unchanged. Inspect the reflected expanded attribute and the button’s aria-expanded value after a change rather than assuming the initial markup is still the current state.

The existing htm with Preact guide renders a document tree from tagged templates. This example registers reusable HTML elements with independent properties and disclosure state. The difference matters when the same behavior appears in several places in one report.

Use the self-contained HTML checklist to inspect the delivery file separately from the component recipe. In particular, the neighboring module named in the recipe must either travel with that version or be packaged into the delivered page; a working custom tag in your project folder is not the attachment you are asking a reviewer to open.

Include what the recipient needs to render

Lit’s production guidance discusses bundling source code and dependencies. An imported package name or neighboring file is still a dependency; saving the visible page alone does not make it part of an attachment.

This example uses the selected lit@3.3.1 bundle obtained for the exercise, with its license notices retained. The complete HTML contains that bundle. The readable bundle and component source are also provided separately for inspection. Keep your maintained project source and selected dependency version together; an embedded reading copy should not become the only editable project record.

For a prepared HTML review in NOS, keep the two excerpts and their disclosure labels understandable in reading order. Recheck the actual page in its viewing environment. No saved disclosure preference, request submission or automatic synchronization is implied.

Finish with both full excerpts available, independent controls and the exact source needed to reproduce the page. Test the packaged file itself, including the initially closed note, before sending it to a reviewer.

Readable selected bundle · Component source

Keep reading