Skip to content

Bug: Hydration support not loaded when Lit elements are used as raw HTML tags (no client:* directives) #6

@piotrekwitkowski

Description

@piotrekwitkowski

Problem

When Lit elements are used as raw HTML custom element tags in .astro or .mdx files (without client:* directives), the SSR renderer produces DSD output correctly, but hydration never activates on the client. Lit's render() appends duplicate content alongside the existing DSD shadow root content.

Root cause

Two separate issues:

1. before-hydration doesn't fire for raw HTML tags

injectScript('before-hydration', ...) only runs on pages with client:* directives. Pages using raw <my-element> tags with a regular <script> import never trigger it. The hydration support module never loads, so Lit doesn't know to reuse existing DSD shadow roots.

2. Script ordering constraint

globalThis.litElementHydrateSupport is a one-shot callback — LitElement checks for it once during class initialization and ignores it after that. With injectScript('page', ...), Vite may evaluate lit before the callback is set, so it's too late. The setup has to be a synchronous inline <script> in <head>.

Additional issue: defer-hydration elements never initialize

Some SSR'd elements get a defer-hydration attribute. The client.js removes it, but only within Astro's client:* flow. Without client:* directives, nothing removes it, so these elements never start up.

Reproduction

---
import '@my-lit-lib';
---
<html>
  <body>
    <my-button variant="primary">Click me</my-button>
    <script>import '@my-lit-lib';</script>
  </body>
</html>

Expected: Single button, interactive after JS loads.
Actual: Button content appears twice in the shadow root.

Fix: #7

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions