夯HumGuides
Back to home

Partial page updates

Use partials to fetch a new page while replacing, appending, or prepending only named regions of the current document.

Mark a region and opt in to client navigation

Wrap the content to update in a Partial with a stable, unique name. Add data-hum-client-nav to an ancestor to intercept same-origin links and GET/POST forms inside it. Matching partials from the fetched page are applied without replacing the surrounding shell.

TypeScript
// routes/docs/partials/[[topic]].tsx — the first demo on this page
import { Partial } from "@humjs/core/client";

export default function PartialsPage({ url }) {
  const topic = url.searchParams.get("topic") ?? "start";

  return (
    <div data-hum-client-nav>
      <a href="/docs/partials/handlers" data-hum-partial="/docs/partials?topic=handlers">
        Handlers
      </a>

      <Partial name="topic">
        <p>{topics[topic]}</p>
      </Partial>
    </div>
  );
}

Keep the partial name consistent between responses. A normal full-page navigation still works when client navigation is not enabled.

Links and forms

Links inside an opted-in region navigate without a full reload. GET and POST forms are also supported; other form methods use normal browser submission. Add data-hum-partial to a link or form when you want to fetch a different URL than the one used for the visible navigation or form action.

TypeScript
// the link navigates to /docs/partials/handlers, but the fetch
// that updates the "topic" region asks for /docs/partials?topic=handlers
<a href="/docs/partials/handlers" data-hum-partial="/docs/partials?topic=handlers">
  Handlers
</a>
For a smaller opt-in area, put data-hum-client-nav only on the wrapper containing the links/forms that should use partial navigation. Set data-hum-client-nav={false} to opt out inside an enabled ancestor.

View Transitions

Hum automatically uses the browser’s View Transitions API for client-side partial navigations when it is available. The transition covers the partial DOM updates and current-link state; no extra attribute or JavaScript setup is needed. Browsers without the API apply the updates normally. You can customize the animation with the standard View Transition pseudo-elements, for example:

CSS
::view-transition-old(root) {
  animation: 180ms ease-out both fade-out;
}

::view-transition-new(root) {
  animation: 180ms ease-out both fade-in;
}

@keyframes fade-out {
  to { opacity: 0; }
}

@keyframes fade-in {
  from { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(root),
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 0s;
  }
}

Choose how new content is applied

The default mode replaces the region’s contents. Use append or prepend for feeds and lists; the existing DOM children are retained and new content is added at the selected edge. The second demo below does both: the list region appends the next batch while the region holding the form is replaced, so the button can move from “Load more” to the end of the list.

replace

Replace the current region contents (default).

append

Add the fetched content after existing children.

prepend

Add the fetched content before existing children.

TypeScript
// handlers: what the "Load more" form below submits to
export const handlers = define.handlers({
  GET: () => page({ hasMore: true }),
  POST: async (c) => {
    const form = await c.req.formData();
    const batch = Number(form.get("batch"));
    const start = batch * LOAD_MORE_BATCH_SIZE;

    return page({
      batch,
      hasMore: start + LOAD_MORE_BATCH_SIZE < LOAD_MORE_ITEMS.length,
    });
  },
});

// one region appends the new items, the other replaces the form
<div data-hum-client-nav>
  <Partial name="load-more-items" mode={batch === undefined ? "replace" : "append"}>
    {itemsForBatch.map((item) => <li>{item}</li>)}
  </Partial>

  <Partial name="load-more-control">
    <form method="post" action="/docs/partials">
      <input type="hidden" name="batch" value={nextBatch} />
      <button>Load more</button>
    </form>
  </Partial>
</div>

If a response does not contain any partial regions, Hum falls back to a full navigation. The URL and browser history stay in sync, and Back / Forward restores the prior page state.

Try it

Update one region

These links change the URL and replace only the matching partial. The surrounding panel stays in place.

Current topic

Pick a topic to update just this panel.

Append mode demo

Load more items

Submit the form to fetch the next two items. The list appends them; only the form area is replaced.

  1. 1Append new content without replacing what is already on screen.
  2. 2Keep the request and rendering on the server.

Previous: Route handlers →