Skip to content

Hydration Directives ​

Hydration directives are HTML attributes on custom elements that tell revive when to load an island's JavaScript. Every island needs at least one directive. These directives are provided by vite-plugin-shopify-theme-islands.

Which directive should I use? ​

ScenarioDirective
Site header, cart drawer — needed early but not at paintclient:idle
Below-the-fold content — product recommendations, footer featuresclient:visible
Viewport-specific — mobile-only nav drawerclient:media="(max-width: 1023px)"
Low-priority — analytics, non-critical widgetsclient:defer
Inert until engaged — expandable FAQ, tooltipclient:interaction

Directive reference ​

DirectiveSyntaxBrowser APITiming
Idleclient:idlerequestIdleCallbackAfter main thread is free (500ms timeout fallback)
Visibleclient:visibleIntersectionObserverWithin 200px of the viewport
Mediaclient:media="(query)"matchMediaWhen the media query matches
Deferclient:defersetTimeout2 seconds after page load
Interactionclient:interactionEvent listenersOn mouseenter, touchstart, or focusin

client:idle ​

Loads when the browser's main thread is free. Falls back to a 500ms timeout if requestIdleCallback isn't available or hasn't fired.

liquid
<sticky-header client:idle>
  <!-- Header markup -->
</sticky-header>

client:visible ​

Loads when the element enters (or nears) the viewport. The 200px rootMargin starts loading slightly before the element is visible.

liquid
<product-recommendations client:visible>
  <!-- Recommendations -->
</product-recommendations>

client:media="(query)" ​

Loads only when a CSS media query matches. If the viewport changes to match later, the island loads then.

liquid
<header-drawer client:media="(max-width: 1023px)">
  <!-- Mobile menu drawer — JS never loads on desktop -->
</header-drawer>

The query must include parentheses: client:media="(max-width: 1023px)", not client:media="max-width: 1023px".

client:defer ​

Loads after a 2-second delay. Good for third-party integrations or components where a slight delay is acceptable.

liquid
<island-demo-defer client:defer>
  <!-- Low-priority content -->
</island-demo-defer>

client:interaction ​

Loads on first mouseenter, touchstart, or focusin. The triggering event fires before hydration completes, so design the HTML to provide appropriate feedback in the non-hydrated state.

liquid
<island-demo-interaction client:interaction>
  <!-- Loads on first hover/touch/focus -->
</island-demo-interaction>

Combining directives ​

An element can have multiple directives. The first condition met triggers the load:

liquid
<my-island client:visible client:interaction>
  <!-- Loads when visible OR when user interacts — whichever comes first -->
</my-island>

How directives are parsed ​

Revive reads all client:* attributes, sets up listeners for each, triggers the dynamic import on the first one that fires, and cleans up the rest. If no directive is present on a recognized custom element, revive does not hydrate it.

Directives are standard HTML attributes — Liquid passes them through without modification. They work in sections, blocks, and snippets:

liquid
<variant-radios client:idle {{ block.shopify_attributes }}>
  <!-- Variant radio buttons -->
</variant-radios>

Next steps ​