Writing HTML modules
An HTML module is an ordinary HTML file. Each <html-export> in it is a public export; everything else is private
to the file. Export names are lower-case words joined by single hyphens (card, fancy-button).
| Export | Markup | Value |
|---|---|---|
| Component | <html-export name="card"><template>…</template></html-export> |
an HTML Component Definition |
| Stylesheet | <html-export name="dark"><style>…</style></html-export> |
an HTMLStylesheet |
| Data | <html-export name="config"><script type="application/json">…</script></html-export> |
the parsed JSON |
| Default | <html-export name="default">…</html-export> (or a bare name) |
the default export, like export default |
| Named and default | <html-export name="card" default>…</html-export> |
card, and also default, like export { card, card as default } |
| Every component of another module | <html-export src="./more.html"></html-export> |
like export * from |
| One export of another module | <html-export src="./b.html" name="button" import="fancy-button"></html-export> |
like export { fancyButton as button } from |
| Several exports of another module | <html-export src="./b.html" names="card, fancy-button as button"></html-export> |
like export { card, fancyButton as button } from |
| Another module as a namespace | <html-export src="./icons.html" name="icon" import="*"></html-export> |
like export * as icon from |
| Another module’s export as the default | <html-export src="./b.html" name="default" import="card"></html-export> |
like export { card as default } from |
All the ESM re-export forms are covered; see Re-exports.
A component export holds exactly one <template>, which is stamped into a shadow root, so native <slot>, named
slots and part work as usual. Its attributes are shadow="open" (default) or shadow="closed", and
delegates-focus. <style> elements beside the template become the component’s styles: one constructed
stylesheet per definition, adopted by every instance’s shadow root. (<style> inside the template works too, but
is cloned into each instance.)
Default exports
Section titled “Default exports”name="default" is the default export. It mirrors JavaScript’s export default, and pairs with
<html-binding export="default" element="…"> on the importing side:
<html-export name="default"><template>…</template></html-export> <!-- export default --><html-export name><template>…</template></html-export> <!-- the same: an empty name --><html-export name="card" default><template>…</template></html-export> <!-- export { card, card as default } -->- A bare
name(an empty value) also means the default. Watch out for templating: a variable that renders asname=""silently becomes a default export. Writename="default"when you mean it. - The
defaultattribute is a modifier for a real name. On its own (<html-export default>) it is an error that points toname="default", andname="default" defaultis an error too. - A module has at most one default, however it is spelled.
defaultandcomponentscannot be named exports. A named re-export can be the default (see Re-exports); star re-exports never pass a default through, as in ESM. - A default-only export has no identity of its own (its definition’s
nameisnull), is not in thecomponentsmanifest, and is not registered byas=: the importer names it withelement=.
Re-exports
Section titled “Re-exports”<html-export src> re-exports another module (HTML or JS), with a counterpart for every ESM form:
| ESM | HTML module |
|---|---|
export * from "./more.html" |
<html-export src="./more.html"></html-export> |
export { card } from "./b.html" |
<html-export src="./b.html" name="card"></html-export> |
export { fancyButton as button } from "./b.html" |
<html-export src="./b.html" name="button" import="fancy-button"></html-export> |
export { card, fancyButton as button } from "./b.html" |
<html-export src="./b.html" names="card, fancy-button as button"></html-export> |
export * as icon from "./icons.html" |
<html-export src="./icons.html" name="icon" import="*"></html-export> |
export { default } from "./b.html" |
<html-export src="./b.html" name="default"></html-export> |
export { card as default } from "./b.html" |
<html-export src="./b.html" name="default" import="card"></html-export> |
export { default as card } from "./b.html" |
<html-export src="./b.html" name="card" import="default"></html-export> |
export { card, card as default } from "./b.html" |
<html-export src="./b.html" name="card" default></html-export> |
- Re-exports keep identity:
barrel.button === b.fancyButton. A missing name fails with ESM’s message,The requested module './b.html' does not provide an export named 'nope', and circular re-exports are rejected. - A namespace re-export’s components also join this module’s manifest as
<name>--<export>, so importing the barrel withas="ui"registers<ui--icon--star>, just as<html-import as="icon">writes<icon--star>inside a module. - A default re-export works like any default-only export: it is not registered by
as=, and the importer names it with<html-binding export="default" element="…">. - Star re-exports follow
export *: nodefault, local names win, and names two sources disagree on are left out.
Modules that import modules
Section titled “Modules that import modules”Modules can import other modules with the same <html-import> element a page uses. Those imports are private to the
module: they are bound when one of the module’s components is registered, and a stylesheet the module adopts
applies inside the module’s components only.
<html-import src="./icons.html" as="icon"></html-import><html-import src="./themes.html"><html-binding export="gold" adopt></html-binding></html-import>
<html-export name="stars"> <template><icon--star></icon--star><icon--star></icon--star><icon--star></icon--star></template></html-export>Every element and attribute, with its validation rules, is in HTML syntax.