Chapter 84: HTML Templates & Slots

Building an Enterprise media-card Component

Designing and shipping a production-ready custom element with multi-slot composition, fallback media, slotted styling tokens, and accessible ARIA attributes.

LEARNING OBJECTIVES
  • Synthesize all Chapter 84 concepts into a production-grade <media-card> Web Component.
  • Architect a 5-slot layout: avatar, header, media, default body, and actions.
  • Implement declarative fallback states for media placeholders and action toolbars.
  • Apply CSS Custom Property theme bridges and ::slotted() styling rules.
  • Bind WAI-ARIA accessibility landmarks and handle dynamic slot mutations via slotchange.
🎬 INTERACTIVE VISUAL PIPELINE Core Architecture Simulation
🌐
1. Input
Directives & Tags
⚙️
2. Parse
Tokenizer & AST
🌳
3. Layout
Box Model & Flow
🎨
4. Render
GPU Paint & Composite
PHASE 1: INPUT & DIRECTIVES
Browser receives declarative markup stream, parsing tag tokens and initializing component state.

📖 The Mental Model & Story (Intuitive Foundation)

Imagine an enterprise design system engineering team at a Fortune 500 media conglomerate.

The design team needs a single, unified Media Card component used across 12 different product surfaces:

  • In the Social Feed, it displays a user avatar, author name, timestamp, an uploaded photo, user captions, and Like/Share buttons.
  • In the Video Streaming Portal, the avatar is omitted, the media slot receives an interactive <video> player, and the action slot contains a "Watch Trailer" button.
  • In the Press Release Feed, the media slot contains a company logo, and the action slot contains a "Download PDF" link.
+-------------------------------------------------------------------------------+
|                       ENTERPRISE <media-card> ANATOMY                         |
+-------------------------------------------------------------------------------+
|                                                                               |
|   +-----------------------------------------------------------------------+   |
|   |  HEADER VIEWPORT:                                                     |   |
|   |  [ <slot name="avatar"> ]  [ <slot name="header"> (Title + Subtitle) ]|   |
|   +-----------------------------------------------------------------------+   |
|   |  MEDIA VIEWPORT:                                                      |   |
|   |                                                                       |   |
|   |  [ <slot name="media"> (Image, Video, or SVG Fallback) ]              |   |
|   |                                                                       |   |
|   +-----------------------------------------------------------------------+   |
|   |  BODY VIEWPORT:                                                       |   |
|   |  [ <slot> (Default Unnamed Slot for Article / Rich Text) ]            |   |
|   +-----------------------------------------------------------------------+   |
|   |  ACTIONS VIEWPORT:                                                    |   |
|   |  [ <slot name="actions"> (Interactive Buttons / Links) ]              |   |
|   +-----------------------------------------------------------------------+   |
|                                                                               |
+-------------------------------------------------------------------------------+

Instead of writing 12 brittle variations with dozens of confusing boolean flags (hasAvatar={true}, mediaType="video", showFooter={false}), the team ships a single, highly composable <media-card> element powered natively by HTML Slots and Templates.


Technical Deep Dive & Specifications

The Enterprise Component Architecture

                                 <media-card>
                                      │
                     ┌────────────────┴────────────────┐
                     │                                 │
              Light DOM Nodes                  Shadow DOM Root
                     │                                 │
      ┌──────────────┼──────────────┐                  ├── Static Template (<template>)
      │              │              │                  ├── Theme Tokens (--media-card-*)
  slot="avatar" slot="header"  slot="media"            ├── Header Grid Layout
      │              │              │                  ├── Media Aspect Ratio Box (16:9)
      └──────────────┼──────────────┘                  ├── Body Padding Container
                     │                                 ├── Actions Flex Toolbar
            Composed Flat Tree                         └── slotchange Event Listeners
                     │                                     (Toggles empty-slot CSS)
                     v
           Rendered Visual Card

Slot Contract & Fallback Specifications

Slot Name Intended Payload Fallback Behavior When Omitted Accessibility / ARIA Role
name="avatar" Circular <img>, <svg>, or avatar badge Renders a neutral geometric avatar placeholder. aria-hidden="true" on decorative avatar.
name="header" <h3> title and metadata spans Renders <h3>Untitled Broadcast</h3>. role="heading" aria-level="3".
name="media" <img>, <video>, or <iframe> Renders a high-contrast blueprint SVG illustration. Media wrapper with semantic <figure>.
(Default) Paragraphs, text blocks, markdown content Renders <p>No description provided.</p>. Body <section>.
name="actions" <button> elements, interactive links Collapses the action bar container (display: none). Toolbar landmark role="toolbar".

Design System Theme Tokens (CSS Custom Properties)

:host {
  --card-bg: #1e293b;
  --card-border: #334155;
  --card-radius: 12px;
  --card-accent: #38bdf8;
  --card-text: #f8fafc;
  --card-subtext: #94a3b8;
}

💻 Interactive Code Playground

Starter Code

Line-by-Line Code Breakdown

  • Line 66–70 (static template = (() => { ... })()): Implements static template compilation. The component's HTML blueprint is parsed only once across all instances.
  • Line 183 (this.actionsSlot.addEventListener('slotchange', ...)): Tracks dynamic mutations to the actions slot.
  • Line 192–198 (syncActionsVisibility()): If the consumer does not provide any action elements, the footer wrapper is automatically hidden (display: none), maintaining clean layout margins.
  • Line 124–129 (::slotted([slot="media"])): Forces any projected <img> or <video> to fill the 16:9 aspect-ratio media container perfectly.

Expected Browser Render Output


SYS: ACTIVE
HULL: 98%
CORE: STABLE
NET: ONLINE
HTML STARSHIP CODE TERMINAL playground.html
LIVE RENDER & DIAGNOSTICS CORE TEMP: 45°C
INSPECTING DOM: VALID
TAGS: SCANNING...
+---------------------------------------------------------------+
| (O) Sarah Connor                                              |
|     Staff Infrastructure Engineer · 2h ago                    |
+---------------------------------------------------------------+
| [ =================== Microchip Photo ===================== ] |
| [ ======================= (16:9) ========================== ] |
+---------------------------------------------------------------+
| Successfully migrated our core telemetry ingestion pipeline   |
| to native Web Components and Web Workers...                   |
+---------------------------------------------------------------+
| [ 💬 Comment ]                                  [ 🚀 Repost ] |
+---------------------------------------------------------------+

🏋️ Hands-On Exercise

🎯 The Challenge: Extend <media-card> with Interactive Like Counter

Instructions:

  1. Use the <media-card> architecture from this lesson.
  2. In the Light DOM action slot, inject an interactive <button slot="actions" class="like-btn">❤️ <span class="like-count">0</span> Likes</button>.
  3. Add a click event handler to the button that increments the like counter and dispatches a custom composed event 'card-liked' with the new total.
  4. Listen for 'card-liked' on the document to demonstrate event traversal across shadow DOM boundaries.

🏁 Starter Code Sandbox

SYS: ACTIVE
HULL: 98%
CORE: STABLE
NET: ONLINE
STARTER CODE SANDBOX exercise.html
LIVE RENDER & DIAGNOSTICS CORE TEMP: 45°C
INSPECTING DOM: VALID
TAGS: SCANNING...

⚠️ Common Pitfalls

  1. Hardcoding Slot Heights Without Aspect Ratios: Fixing media slot heights to height: 200px causes distortion on mobile screens. Always use modern CSS aspect-ratio: 16 / 9; on the slot wrapper.
  2. Forgetting Fallback Dimensions: If an SVG fallback inside <slot name="media"> has no explicit width, height, or viewBox, it may collapse to 0 pixels in some browser rendering engines.
  3. Unnecessary Wrapper <div> Bloat in Consumer Markup: Consumers do not need to wrap every text element in a <div> to slot it; simple <h3 slot="header"> or <button slot="actions"> tags slot directly.

💡 Pro Tips

  1. CSS Part Exposure (::part): In addition to slots, expose structural styling hooks using part="header", part="media", and part="footer" on internal shadow wrappers so design system consumers can customize padding and background styles seamlessly.
  2. Constructable Stylesheets Integration: In production enterprise libraries, combine <template> stamping with shadowRoot.adoptedStyleSheets = [sharedSheet] to share CSS rule caches across thousands of <media-card> instances.

📌 Key Takeaways

  • Multi-slot composition enables complex enterprise components with clean, declarative consumer APIs.
  • Declarative fallback content allows components to render beautifully even when optional slots are omitted.
  • Use slotchange to dynamically synchronize container visibility when optional toolbars are empty.
  • ::slotted([slot="media"]) ensures projected media elements automatically conform to component layout rules.
  • Static template compilation maximizes memory reuse and delivers near-instantaneous component instantiation.
  • --
⭐ LEARN: HTML 🌟 ⚔️ QUIZ BATTLE ARENA // ACTIVE
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 1 / 3

Why is compiling the master <template> as a static class property (static template = ...) a recommended architectural pattern for Web Components?

Question 1 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 2 / 3

How can a <media-card> automatically hide its footer action bar container when the consumer provides no elements matching slot="actions"?

Question 2 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 3 / 3

Which CSS selector inside the component's Shadow DOM ensures that any image projected into slot="media" fills the 16:9 container without distortion?

Question 3 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP