Skip to content
Ilha
Esc
navigateopen⌘Jpreview
On this page

View Transitions

You animate between UI states with the browser’s native View Transition API. Ilha doesn’t wrap it — you call document.startViewTransition() and update state inside the callback.

import { const ilha: IlhaFactoryilha, function state<T>(init?: T | (() => T)): StateAccessor<T>
Declare island-local reactive state at this call position. The initializer applies only when the instance is created — later renders reuse the same underlying signal, so prop-driven initializers never reset user state. A function argument is treated as a lazy initializer: const count = state(() => expensiveInitialValue()); To store a function VALUE, return it from the updater wrapper on write: setCallback(() => nextCallback);
state
} from "ilha";
export default ilha<unknown>(component: IslandComponent<unknown>): Island<unknown> (+3 overloads)ilha(() => { const const checked: StateAccessor<boolean>checked = state<boolean>(init?: boolean | (() => boolean) | undefined): StateAccessor<boolean>
Declare island-local reactive state at this call position. The initializer applies only when the instance is created — later renders reuse the same underlying signal, so prop-driven initializers never reset user state. A function argument is treated as a lazy initializer: const count = state(() => expensiveInitialValue()); To store a function VALUE, return it from the updater wrapper on write: setCallback(() => nextCallback);
state
(false);
const const toggle: () => voidtoggle = () => { var document: Document
**`window.document`** returns a reference to the document contained in the window. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/document)
document
.Document.startViewTransition(callbackOptions?: ViewTransitionUpdateCallback | StartViewTransitionOptions): ViewTransition
The **`startViewTransition()`** method of the Document interface starts a new same-document (SPA) view transition and returns a ViewTransition object to represent it. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Document/startViewTransition)
startViewTransition
(() => {
const checked: MarkedSignalAccessor
(value: SignalSetter<boolean>) => void (+1 overload)
checked
(!
const checked: MarkedSignalAccessor
() => boolean (+1 overload)
checked
());
}); }; return ( <
"button": WithRawHtmlAttributeValues<JSX.HTMLAttributes<HTMLButtonElement> & ButtonAttributes & {
    popovertarget?: string;
    popoverTarget?: string;
    popovertargetaction?: "hide" | "show" | "toggle";
    popoverTargetAction?: "hide" | "show" | "toggle";
}>
button
class?: RawHtml | ClassValue | undefinedclass="card"
onclick?: NativeEventHandler<PointerEvent & {
    readonly currentTarget: HTMLButtonElement;
}> | undefined
onclick
={const toggle: () => voidtoggle}
style?: string | RawHtml | StyleProps | undefinedstyle="view-transition-name: card" > {
const checked: MarkedSignalAccessor
() => boolean (+1 overload)
checked
() ? "Checked" : "Unchecked"}
</
"button": WithRawHtmlAttributeValues<JSX.HTMLAttributes<HTMLButtonElement> & ButtonAttributes & {
    popovertarget?: string;
    popoverTarget?: string;
    popovertargetaction?: "hide" | "show" | "toggle";
    popoverTargetAction?: "hide" | "show" | "toggle";
}>
button
>
); });

How it works

startViewTransition(callback) snapshots the current page, runs callback (where you write new state), then cross-fades between the old and new snapshots.

You wrap only the state write — the island re-renders and morph() patches the DOM inside the transition, so the browser animates the change.

Name shared elements

The same element before and after the change must carry the same view-transition-name for the browser to morph it.

.card {
  view-transition-name: card;
}

Respect the reduced-motion setting

import { state } from "ilha";

const checked = state(false);

const toggle = () => {
  const reduce = matchMedia(
    "(prefers-reduced-motion: reduce)",
  ).matches;
  const write = () => checked(!checked());
  if (reduce) {
    write();
  } else {
    document.startViewTransition(write);
  }
});

Was this page helpful?