skip to content

On a long server-rendered Angular product page, which hydrate triggers would you give the add-to-basket panel, the comments section and the legal footer, and why?

level: seniorimportance: should knowfreq 40%

answer

  1. visible already; when interactive?
  2. interaction vs idle for key controls
  3. viewport for below the fold
  4. never for static content

basics

~10 s

Choose by when each block must respond: hydrate on idle or interaction for the add-to-basket panel, hydrate on viewport for comments far below the fold, and hydrate never for a static footer.

solid answer

~40 s

Every block is already visible as server HTML, so I pick a trigger by when it must become interactive. The comments section sits far below the fold, so `hydrate on viewport`: its code loads only for readers who scroll there. The legal footer is static text and links, so `hydrate never`, provided nothing inside needs Angular handlers. The add-to-basket panel is visible at once and conversion-critical: `hydrate on interaction` saves the most bytes, but on a slow network the first click waits for the download even though event replay keeps it, so `hydrate on idle` is often the better trade. Hover-driven helpers like a size guide suit `hydrate on hover`. Remember nested blocks hydrate from the outside in, and measure the result.

code

html · 23 lines
html
@defer (hydrate on idle) {
  <app-add-to-basket [sku]="sku()" />
} @placeholder {
  <div class="basket-skeleton"></div>
}

@defer (hydrate on hover) {
  <app-size-guide />
} @placeholder {
  <span>Size guide</span>
}

@defer (hydrate on viewport) {
  <app-product-comments [productId]="productId()" />
} @placeholder {
  <p>Comments</p>
}

@defer (hydrate never) {
  <app-legal-footer />
} @placeholder {
  <footer class="footer-skeleton"></footer>
}

go deeper

for a junior

Recall what each hydrate trigger waits for: idle, viewport, interaction, hover, immediate, timer, a condition, or never.

for a middle

Explain why the choice depends on when a block must respond rather than when it must be seen, and match triggers to typical page sections.

for a senior

Balance saved startup code against the first-use delay on key controls, audit hydrate never sections, and account for outer blocks pulled in by inner triggers.

for a principal

Set page-level conventions for hydration boundaries and back them with measurements of startup script and time to interactive.

## The page A long product page is server-rendered. From top to bottom it has: a header with a search box, the image gallery and **add-to-basket** panel, a size guide that opens on hover, a reviews and **comments** section far below the fold, a "recently viewed" carousel, and a large legal **footer**. Every section is wrapped in `@defer` so that each can choose when it becomes interactive. ## The available hydrate triggers | Trigger | Fires when | Good for | | --- | --- | --- | | `hydrate on immediate` | Right after non-deferred content has rendered | Content needed at once, but worth splitting into its own chunk | | `hydrate on idle` | The browser is idle (`requestIdleCallback`), optionally with a timeout such as `hydrate on idle(500)` | Content that should be ready soon but must not compete with startup | | `hydrate on viewport` | The block's content enters the viewport | Long pages: sections below the fold | | `hydrate on interaction` | The user clicks or presses a key on the block (`click`, `keydown`) | Controls that do nothing until used | | `hydrate on hover` | The pointer hovers or focus enters (`mouseover`, `focusin`) | Tooltips, previews, menus that open on hover | | `hydrate on timer(2s)` | After a fixed delay, in `ms` or `s` | Rarely the best choice; a guess at timing | | `hydrate when expr` | A condition in the parent becomes truthy | Hydrating on application state | | `hydrate never` | Never, on the initial load | Content that is purely static | Several hydrate triggers can be combined with semicolons; hydration starts when **any** of them fires. `hydrate never` cannot be combined with other hydrate triggers. ## A defensible assignment 1. **Add-to-basket panel: `hydrate on interaction`, or `hydrate on idle` if it must feel instant.** It is visible immediately but only matters when used. With `on interaction` the first click starts the download and is replayed afterwards; on slow networks that first click waits, so a conversion-critical control often justifies `on idle` instead. 2. **Size guide: `hydrate on hover`.** Hover and focus precede the click, which hides most of the download. 3. **Comments section: `hydrate on viewport`.** Far below the fold, it becomes interactive as the reader scrolls to it, and its code is never downloaded for visitors who leave earlier. 4. **Recently viewed carousel: `hydrate on viewport`**, for the same reason. 5. **Legal footer: `hydrate never`.** It is static text and links; the HTML is enough. 6. **Header search box: not deferred, or `hydrate on immediate`.** It is used early and often; delaying it is a poor trade. ## Judgement calls behind the table - **Visible is not the question; interactive is.** Every block is already visible as server HTML, so choose by when a user can need it to respond. - **Interaction triggers make the first use pay for the download.** Event replay prevents the click being lost, not the wait. - **`hydrate never` really means inert.** Any `(click)` inside such a block will not work on the initial load, so audit it for links that rely on Angular handlers. - **Nested blocks hydrate from the outside in.** Hydrating an inner block first hydrates its dehydrated parents, so a cheap inner trigger inside an expensive outer block pulls the outer code too. - **Measure.** Compare startup JavaScript and time-to-interactive for the key controls before and after; a trigger is a hypothesis about user behaviour. ## Where this goes wrong - Deferring everything with `hydrate on viewport`, including the add-to-basket panel above the fold, which then hydrates almost at once because it is already in the viewport, adding a separate chunk request for little gain. - Using `hydrate on timer` as a crude "later", which ignores both idleness and user intent. - Marking a section `hydrate never` and later adding an interactive widget inside it.

  • Why can hydrate on interaction feel slow for a key control?
    The first click is what starts fetching the block's code. Event replay makes sure the click is handled afterwards, but the user still waits for the download and hydration, so critical controls often use `hydrate on idle` or no deferral.
  • What must you check before marking a section hydrate never?
    That nothing inside relies on Angular listeners or bindings on the first load, because the subtree stays static and no nested hydrate trigger will fire. Plain links and text are fine; a filter or a button with a `(click)` handler is not.

saying these in an interview costs you the question

  • Blocks with hydrate on viewport are invisible until scrolled to
  • Event replay removes any delay from hydrate on interaction
  • hydrate on viewport is the right default for every block
  • A widget inside a hydrate never block will hydrate on its own trigger
  • hydrate on timer is the most reliable way to hydrate later