<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>Foldkit Blog</title>
<link>https://foldkit.dev/blog</link>
<atom:link href="https://foldkit.dev/blog/rss.xml" rel="self" type="application/rss+xml" />
<description>Announcements, musings, and technical deep dives.</description>
<lastBuildDate>Sat, 19 Sep 2026 00:00:00 GMT</lastBuildDate>
<item>
  <title>Foldkit 0.162.0 and 0.163.0</title>
  <link>https://foldkit.dev/blog/foldkit-0-163-0</link>
  <guid>https://foldkit.dev/blog/foldkit-0-163-0</guid>
  <description>Swipe-to-dismiss on Toast, clearer names for Model updates and key bindings, explicit canonical URLs, and SSR builds that no longer publish an unrendered HTML template.</description>
  <pubDate>Sat, 19 Sep 2026 00:00:00 GMT</pubDate>
  <enclosure url="https://foldkit.dev/blog/foldkit-0-163-0/cover.webp" length="152864" type="image/webp" />
  <content:encoded><![CDATA[<article data-foldkit-identity="76a96447eaadcc72"><div class="relative overflow-hidden rounded-lg mb-8" data-foldkit-identity="80a2c6e532125e5c"><div class="absolute inset-0 bg-gray-200 dark:bg-gray-800 animate-pulse"></div><img width="3600" height="2400" class="relative w-full h-auto" src="https://foldkit.dev/blog/foldkit-0-163-0/cover.webp" alt="Blue cloud imagery fills 162, overlapping an orange and pale pink 163 on a dark background."></div><header class="mb-8"><h1 data-pagefind-meta="section" class="font-heading font-book text-page-title md:text-page-title-wide leading-tight tracking-tight text-gray-900 dark:text-white mb-3" id="foldkit-0-163-0" data-foldkit-identity="89d40481a105ec00">Foldkit 0.162.0 and 0.163.0</h1><p class="text-gray-500 dark:text-gray-400">September 19, 2026 · Devin Jameson</p></header><div data-foldkit-identity="8fed9e3a5e2e9719"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Foldkit 0.163.0 is out. This post also covers 0.162.0.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">These releases add swipe-to-dismiss on Toast, make canonical URLs an application decision, keep unrendered HTML out of SSR client output, and give several familiar APIs clearer names.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="swipe-to-dismiss-on-toast">Swipe-to-dismiss on Toast</h2><a aria-label="Copy link to Swipe-to-dismiss on Toast" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#swipe-to-dismiss-on-toast" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Toast entries can now follow your pointer and dismiss with a swipe. The <a class="link-accent" href="https://foldkit.dev/ui/toast#gestures" data-foldkit-identity="b9c1739f4bc7044a">Toast guide</a> covers configuration and styling.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Thank you to <a class="link-accent" href="https://github.com/elianiva" data-foldkit-identity="b9c1739f4bc7044a">@elianiva</a> for <a class="link-accent" href="https://github.com/foldkit/foldkit/pull/1295" data-foldkit-identity="b9c1739f4bc7044a">contributing the implementation</a>!</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="evo-renamed-to-modifyfields">evo renamed to modifyFields</h2><a aria-label="Copy link to evo renamed to modifyFields" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#evo-renamed-to-modifyfields" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">evo</code> has been renamed to <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">modifyFields</code>. It was the last function in the core Foldkit API whose name was cute rather than clear. <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">makeConstrainedEvo</code> has also been renamed <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">makeModifyFieldsFor</code>. The behavior is unchanged.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="explicit-canonical-urls">Explicit canonical URLs</h2><a aria-label="Copy link to Explicit canonical URLs" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#explicit-canonical-urls" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Applications now choose their canonical URLs explicitly through <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Document.canonical</code>. This lets the application decide whether a query parameter identifies different content or is just tracking information. The <a class="link-accent" href="https://foldkit.dev/core/view#the-document" data-foldkit-identity="b9c1739f4bc7044a">Document guide</a> covers the setup.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="ssr-builds-no-longer-emit-an-unrendered-index-html">SSR builds no longer emit an unrendered index.html</h2><a aria-label="Copy link to SSR builds no longer emit an unrendered index.html" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#ssr-builds-no-longer-emit-an-unrendered-index-html" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">SSR builds no longer include an unrendered <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">index.html</code> template among the browser assets. This prevents static hosts from serving that template as a blank page. Prerendered pages are still generated normally.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Thank you to <a class="link-accent" href="https://github.com/filipfalcon" data-foldkit-identity="b9c1739f4bc7044a">@filipfalcon</a> for the <a class="link-accent" href="https://github.com/foldkit/foldkit/pull/1387" data-foldkit-identity="b9c1739f4bc7044a">canonical URL</a> and <a class="link-accent" href="https://github.com/foldkit/foldkit/pull/1388" data-foldkit-identity="b9c1739f4bc7044a">SSR build</a> changes!</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="more-in-these-releases">More in these releases</h2><a aria-label="Copy link to More in these releases" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#more-in-these-releases" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><ul class="list-disc mb-6 space-y-2 [&amp;>li>p:last-child]:mb-0" data-foldkit-identity="408d5615f6a4615c"><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Fixed a startup bug that could leave Subscriptions and ManagedResources out of sync with the Model. Thank you to <a class="link-accent" href="https://github.com/WikiRik" data-foldkit-identity="b9c1739f4bc7044a">@WikiRik</a> for <a class="link-accent" href="https://github.com/foldkit/foldkit/issues/1404" data-foldkit-identity="b9c1739f4bc7044a">reporting the timing bug with a runnable reproduction</a>!</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">h.OnPointerDown</code> callbacks now receive <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">pointerId</code> and the event target.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Anchor now explains why an invalid trigger or panel prevents positioning.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Subscription.fromEvent</code> and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Subscription.keyBindings</code> now call their mapper <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">mapEvent</code>; <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">fromEventFilterMap</code> and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">fromEventFilterMapPreventDefault</code> use <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">filterMapEvent</code>.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">In 0.162.0, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Subscription.keyboardShortcuts</code> became <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Subscription.keyBindings</code>, and each binding's <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">shortcut</code> field became <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">keys</code>. The <a class="link-accent" href="https://foldkit.dev/core/subscriptions#key-bindings" data-foldkit-identity="b9c1739f4bc7044a">Subscriptions guide</a> shows the current API.</p></li></ul><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The full <a class="link-accent" href="https://github.com/foldkit/foldkit/releases/tag/foldkit%400.162.0" data-foldkit-identity="b9c1739f4bc7044a">0.162.0</a> and <a class="link-accent" href="https://github.com/foldkit/foldkit/releases/tag/foldkit%400.163.0" data-foldkit-identity="b9c1739f4bc7044a">0.163.0</a> release notes cover every package and migration detail.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Thanks to everyone building with Foldkit!</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Devin</p></div></article>]]></content:encoded>
</item>
<item>
  <title>Foldkit 0.160.0 and 0.161.0</title>
  <link>https://foldkit.dev/blog/foldkit-0-161-0</link>
  <guid>https://foldkit.dev/blog/foldkit-0-161-0</guid>
  <description>Accessibility fixes across Foldkit UI, declarative keyboard shortcuts, helpers for initializing Submodels, stronger lint checks, and improved type inference.</description>
  <pubDate>Thu, 17 Sep 2026 00:00:00 GMT</pubDate>
  <enclosure url="https://foldkit.dev/blog/foldkit-0-161-0/cover.webp" length="166384" type="image/webp" />
  <content:encoded><![CDATA[<article data-foldkit-identity="76a96447eaadcc72"><div class="relative overflow-hidden rounded-lg mb-8" data-foldkit-identity="80a2c6e532125e5c"><div class="absolute inset-0 bg-gray-200 dark:bg-gray-800 animate-pulse"></div><img width="3600" height="2400" class="relative w-full h-auto" src="https://foldkit.dev/blog/foldkit-0-161-0/cover.webp" alt="Rows of 160 and 161 in cyan and yellow, joined by plus signs, with tilted coral and lime digits on a light gray background."></div><header class="mb-8"><h1 data-pagefind-meta="section" class="font-heading font-book text-page-title md:text-page-title-wide leading-tight tracking-tight text-gray-900 dark:text-white mb-3" id="foldkit-0-161-0" data-foldkit-identity="89d40481a105ec00">Foldkit 0.160.0 and 0.161.0</h1><p class="text-gray-500 dark:text-gray-400">September 17, 2026 · Devin Jameson</p></header><div data-foldkit-identity="8fed9e3a5e2e9719"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Foldkit 0.161.0 is out. This post also covers 0.160.0.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">These releases:</p><ul class="list-disc mb-6 space-y-2 [&amp;>li>p:last-child]:mb-0" data-foldkit-identity="408d5615f6a4615c"><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Improve accessibility across Foldkit UI.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Add declarative keyboard shortcuts.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Introduce helpers for initializing Submodels.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Add lint checks that catch more mistakes at Submodel boundaries.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Reduce the explicit type arguments needed for Subscriptions and ManagedResources.</p></li></ul><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="accessibility-improvements-across-foldkit-ui">Accessibility improvements across Foldkit UI</h2><a aria-label="Copy link to Accessibility improvements across Foldkit UI" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#accessibility-improvements-across-foldkit-ui" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Foldkit UI received an AI accessibility audit resulting in several fixes.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-12 mb-3 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h3 class="font-heading font-book text-xl md:text-2xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="background-isolation-in-modal-dialogs">Background isolation in modal Dialogs</h3><a aria-label="Copy link to Background isolation in modal Dialogs" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#background-isolation-in-modal-dialogs" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">A modal Dialog's backdrop blocked pointer interaction, and its focus trap kept Tab inside the Dialog, but a screen-reader user could still read past it into the page behind the backdrop.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Modal Dialogs now make background content inert and hide it from assistive technology, including new content mounted while the modal is open. Dialogs stacked above the modal remain available. Closing stacked Dialogs out of order also restores focus to an available target.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-12 mb-3 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h3 class="font-heading font-book text-xl md:text-2xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="initially-open-dialogs">Initially open Dialogs</h3><a aria-label="Copy link to Initially open Dialogs" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#initially-open-dialogs" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">A Dialog should provide the same focus management, scroll locking, and screen-reader isolation whether it starts open or opens later. Previously, Dialogs that started open skipped the normal opening setup. This release makes them run that setup too.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">This changes initialization: <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Dialog.init</code> always creates a closed Dialog and no longer accepts <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">isOpen</code>. Remove <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">isOpen: false</code> from existing calls. For an initially open Dialog, pass <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Dialog.boot({ id })</code> to the new <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Update.foldChildInit</code> helper to build the parent Model, lift the Commands, and handle the OutMessage. The <a class="link-accent" href="https://foldkit.dev/ui/dialog" data-foldkit-identity="b9c1739f4bc7044a">Dialog guide</a> covers the complete setup.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-12 mb-3 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h3 class="font-heading font-book text-xl md:text-2xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="other-accessibility-fixes">Other accessibility fixes</h3><a aria-label="Copy link to Other accessibility fixes" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#other-accessibility-fixes" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><ul class="list-disc mb-6 space-y-2 [&amp;>li>p:last-child]:mb-0" data-foldkit-identity="408d5615f6a4615c"><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Controls emit <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">aria-controls</code> only while the referenced panel exists. Tabs that keep every panel mounted should pass <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">panelMount: 'All'</code>.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">A Combobox with no matching items no longer reports a nonexistent active option or expanded listbox. Its modal backdrop remains available for dismissal.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Toast containers and entries use <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">div</code> elements so their live-region roles do not conflict with list semantics. Update CSS selectors or DOM queries that target the old <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">ol</code> and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">li</code> wrappers.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The website's scrollable tables and virtual lists are named and keyboard-focusable. The DragAndDrop demo announces keyboard interactions, and UI pages have improved text contrast.</p></li></ul><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Thank you to <a class="link-accent" href="https://github.com/artile" data-foldkit-identity="b9c1739f4bc7044a">@artile</a> for the accessibility audit and follow-up reports, and to <a class="link-accent" href="https://github.com/sandias42" data-foldkit-identity="b9c1739f4bc7044a">@sandias42</a> for reporting the Toast semantics issue in a downstream application!</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="declarative-keyboard-shortcuts">Declarative keyboard shortcuts</h2><a aria-label="Copy link to Declarative keyboard shortcuts" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#declarative-keyboard-shortcuts" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Prior to this release, adding keyboard shortcuts to a Foldkit application was cumbersome. You had to recognize key combinations, track sequences, manage timeouts, and avoid interrupting text input. These are details a good framework should handle for you.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">In 0.161.0, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Subscription.keyboardShortcuts</code> handles that work from a binding table:</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">const</span><span style="color:#885A06;--shiki-dark:#FFCA58"> shortcuts</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> =</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Subscription</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">keyboardShortcuts</span><span style="color:#625E75;--shiki-dark:#9E9BAA">&#x3C;</span><span style="color:#0E7490;--shiki-dark:#49CAE4">Message</span><span style="color:#625E75;--shiki-dark:#9E9BAA">></span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  bindings</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> [</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">    {</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">      shortcut</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#3D6B06;--shiki-dark:#BCDF59"> 'Mod+K'</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">      whileTyping</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#3D6B06;--shiki-dark:#BCDF59"> 'Allow'</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#6B5CB8;--shiki-dark:#A093E2">      toMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> ()</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#885A06;--shiki-dark:#FFCA58"> Message</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">PressedSearchShortcut</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">()</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">    },</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">    {</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">      shortcut</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> [</span><span style="color:#3D6B06;--shiki-dark:#BCDF59">'G'</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#3D6B06;--shiki-dark:#BCDF59"> 'H'</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">]</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#6B5CB8;--shiki-dark:#A093E2">      toMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> ()</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#885A06;--shiki-dark:#FFCA58"> Message</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">PressedHomeShortcut</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">()</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">    },</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  ]</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy search and home shortcuts to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Mod</code> means Command on Apple platforms and Control elsewhere. An array describes an ordered sequence, so <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">['G', 'H']</code> means press G, then H. Incomplete sequences expire, and ambiguous bindings are rejected when the table is constructed.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Shortcuts ignore editable elements, IME composition, and held-key repeats by default. Here, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">whileTyping: 'Allow'</code> lets the search shortcut work inside a text field. Matched presses cancel their browser default before the listener returns unless a binding sets <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">preventDefault: false</code>. The update function still decides how the application responds to each Message.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The <a class="link-accent" href="https://foldkit.dev/core/subscriptions#key-bindings" data-foldkit-identity="b9c1739f4bc7044a">Subscriptions guide</a> covers the options, and the <a class="link-accent" href="https://foldkit.dev/example-apps/routing" data-foldkit-identity="b9c1739f4bc7044a">routing example</a> demonstrates sequence navigation.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Thank you to <a class="link-accent" href="https://github.com/artile" data-foldkit-identity="b9c1739f4bc7044a">@artile</a> for proposing and contributing the shortcut helper, and to <a class="link-accent" href="https://github.com/hdoro" data-foldkit-identity="b9c1739f4bc7044a">@hdoro</a> for helping shape its API, including conditional shortcuts and key sequences!</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="canceling-default-browser-actions">Canceling default browser actions</h2><a aria-label="Copy link to Canceling default browser actions" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#canceling-default-browser-actions" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">To reliably stop a key press from scrolling the page, cancel its default action inside the event listener.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">0.160.0 added <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Subscription.fromEventFilterMapPreventDefault</code>. When its <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">toMessage</code> callback returns <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Option.some(message)</code>, the helper cancels the browser's default action and queues the Message before the listener returns. The Stream processes the Message after the event listener returns. Returning <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Option.none()</code> leaves the default action alone. DragAndDrop now uses this helper so Tab does not move focus and Space and arrow keys do not scroll the page during a keyboard drag.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The <a class="link-accent" href="https://foldkit.dev/core/subscriptions#dom-events" data-foldkit-identity="b9c1739f4bc7044a">DOM events guide</a> covers event filtering and default cancellation.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="initializing-submodels">Initializing Submodels</h2><a aria-label="Copy link to Initializing Submodels" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#initializing-submodels" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Prior to this release, a parent's init function had to assemble child Submodels by hand: place each child's Model in the parent Model, lift the child's Commands, and handle its OutMessages.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Now, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Update.foldChildInit</code> keeps that work together. For example, a parent can initialize a Search Submodel and reuse the OutMessage fold it already calls from update:</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">const</span><span style="color:#6B5CB8;--shiki-dark:#A093E2"> init</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> =</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> ()</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">  Update</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">foldChildInit</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#885A06;--shiki-dark:#FFCA58">Search</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">boot</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">()</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span></span>
<span class="line"><span style="color:#6B5CB8;--shiki-dark:#A093E2">    toParentModel</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> search</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#885A06;--shiki-dark:#FFCA58"> Model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">make</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span><span style="color:#885A06;--shiki-dark:#FFCA58"> search</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> }</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#6B5CB8;--shiki-dark:#A093E2">    toParentMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> message</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#885A06;--shiki-dark:#FFCA58"> Message</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">GotSearchMessage</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span><span style="color:#885A06;--shiki-dark:#FFCA58"> message</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> }</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">    foldOutMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> foldSearchOutMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">  }</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy folding a child boot result into its parent to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">toParentModel</code> constructs the parent Model before the OutMessage handler runs. The helper lifts the child's Commands and includes any Commands the handler returns.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">For several sibling Submodels, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Update.foldChildInits</code> takes named results and their corresponding folds:</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">const</span><span style="color:#6B5CB8;--shiki-dark:#A093E2"> init</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> =</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> ()</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">  Update</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">foldChildInits</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">    {</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> search</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Search</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">boot</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">()</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> editor</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Editor</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">boot</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">() </span><span style="color:#625E75;--shiki-dark:#9E9BAA">},</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">    {</span></span>
<span class="line"><span style="color:#6B5CB8;--shiki-dark:#A093E2">      toParentModel</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> ({</span><span style="color:#885A06;--shiki-dark:#FFCA58"> search</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#885A06;--shiki-dark:#FFCA58"> editor</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> })</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#885A06;--shiki-dark:#FFCA58"> Model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">make</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span><span style="color:#885A06;--shiki-dark:#FFCA58"> search</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#885A06;--shiki-dark:#FFCA58"> editor</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> }</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">      folds</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">        search</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span></span>
<span class="line"><span style="color:#6B5CB8;--shiki-dark:#A093E2">          toParentMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> message</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#885A06;--shiki-dark:#FFCA58"> Message</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">GotSearchMessage</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span><span style="color:#885A06;--shiki-dark:#FFCA58"> message</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> }</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">          foldOutMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> foldSearchOutMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">        },</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">        editor</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span></span>
<span class="line"><span style="color:#6B5CB8;--shiki-dark:#A093E2">          toParentMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> message</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#885A06;--shiki-dark:#FFCA58"> Message</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">GotEditorMessage</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span><span style="color:#885A06;--shiki-dark:#FFCA58"> message</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> }</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">          foldOutMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> foldEditorOutMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">        },</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">      },</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">    },</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  )</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy initializing Search and Editor Submodels together to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The parent Model is constructed once with both children. Each OutMessage handler receives the parent Model produced by the previous handler, so changes from Search's handler are still present when Editor's handler runs. Commands returned by the children and handlers still run independently.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Both helpers are optional additions. Existing initialization code remains valid. The <a class="link-accent" href="https://foldkit.dev/core/update#combining-independent-results" data-foldkit-identity="b9c1739f4bc7044a">Update guide</a> covers the full setup.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="stronger-lint-checks">Stronger lint checks</h2><a aria-label="Copy link to Stronger lint checks" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#stronger-lint-checks" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Updating a child Model directly can skip the child's validation, Commands, and OutMessages. Copying only the Model from a child result can discard its Commands and OutMessage. These are mistakes the linter should help you catch.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">0.161.0 adds two recommended lint rules that use a parent's existing folds to identify its Submodels:</p><ul class="list-disc mb-6 space-y-2 [&amp;>li>p:last-child]:mb-0" data-foldkit-identity="408d5615f6a4615c"><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><a class="link-accent" href="https://foldkit.dev/tooling/oxlint-plugin#no-direct-submodel-state-update" data-foldkit-identity="b9c1739f4bc7044a"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">no-direct-submodel-state-update</code></a> catches nested <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">evo</code> writes into a child Model that bypass the child's operations.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><a class="link-accent" href="https://foldkit.dev/tooling/oxlint-plugin#require-fold-for-child-update-result" data-foldkit-identity="b9c1739f4bc7044a"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">require-fold-for-child-update-result</code></a> catches copying only a child result's <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">.model</code>, which can discard its Commands and OutMessage.</p></li></ul><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">0.160.0 added six more recommended checks:</p><ul class="list-disc mb-6 space-y-2 [&amp;>li>p:last-child]:mb-0" data-foldkit-identity="408d5615f6a4615c"><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><a class="link-accent" href="https://foldkit.dev/tooling/oxlint-plugin#acquire-release-constructs-in-acquire-body" data-foldkit-identity="b9c1739f4bc7044a"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">acquire-release-constructs-in-acquire-body</code></a> catches resources constructed before the acquire Effect runs, which can leak on interruption.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><a class="link-accent" href="https://foldkit.dev/tooling/oxlint-plugin#prefer-option-over-nullable-in-model" data-foldkit-identity="b9c1739f4bc7044a"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">prefer-option-over-nullable-in-model</code></a> requires direct Model fields to represent absence with <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Schema.Option</code>.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><a class="link-accent" href="https://foldkit.dev/tooling/oxlint-plugin#no-route-query-constructor-default" data-foldkit-identity="b9c1739f4bc7044a"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">no-route-query-constructor-default</code></a> catches constructor defaults in <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Route.query</code> that never run during decoding.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><a class="link-accent" href="https://foldkit.dev/tooling/oxlint-plugin#no-switch-on-message-tag" data-foldkit-identity="b9c1739f4bc7044a"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">no-switch-on-message-tag</code></a> directs Message and state dispatch through exhaustive matchers.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><a class="link-accent" href="https://foldkit.dev/tooling/oxlint-plugin#prefer-command-mapmessage" data-foldkit-identity="b9c1739f4bc7044a"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">prefer-command-mapmessage</code></a> requires Message lifts to use <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Command.mapMessage</code> or <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Command.mapMessages</code> so Story and Scene can recover the mapping.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><a class="link-accent" href="https://foldkit.dev/tooling/oxlint-plugin#no-prevent-default-in-stream-operator" data-foldkit-identity="b9c1739f4bc7044a"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">no-prevent-default-in-stream-operator</code></a> flags cancellation in downstream Stream operators and points you to <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Subscription.fromEventFilterMapPreventDefault</code>.</p></li></ul><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The <a class="link-accent" href="https://foldkit.dev/tooling/oxlint-plugin" data-foldkit-identity="b9c1739f4bc7044a">linting guide</a> explains the rules. Existing applications using the recommended preset may report new errors after upgrading.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="less-type-annotation-for-subscriptions-and-managedresources">Less type annotation for Subscriptions and ManagedResources</h2><a aria-label="Copy link to Less type annotation for Subscriptions and ManagedResources" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#less-type-annotation-for-subscriptions-and-managedresources" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">If you're listening for <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">keydown</code> on <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">window</code>, Foldkit has enough information to know you'll receive a <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">KeyboardEvent</code>. You shouldn't have to spell that out.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">DOM event helpers now infer that type from the target and event name.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Before:</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">const</span><span style="color:#885A06;--shiki-dark:#FFCA58"> keydown</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> =</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Subscription</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">fromEvent</span><span style="color:#625E75;--shiki-dark:#9E9BAA">&#x3C;</span><span style="color:#0E7490;--shiki-dark:#49CAE4">KeyboardEvent</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#0E7490;--shiki-dark:#49CAE4"> Message</span><span style="color:#625E75;--shiki-dark:#9E9BAA">></span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  target</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> window</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  type</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#3D6B06;--shiki-dark:#BCDF59"> 'keydown'</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#6B5CB8;--shiki-dark:#A093E2">  toMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> event</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#885A06;--shiki-dark:#FFCA58"> Message</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">PressedKey</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> key</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> event</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">key </span><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy event types before 0.161.0 to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">After:</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">const</span><span style="color:#885A06;--shiki-dark:#FFCA58"> keydown</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> =</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Subscription</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">fromEvent</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  target</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> window</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  type</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#3D6B06;--shiki-dark:#BCDF59"> 'keydown'</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#6B5CB8;--shiki-dark:#A093E2">  toMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> event</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#885A06;--shiki-dark:#FFCA58"> Message</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">PressedKey</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> key</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> event</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">key </span><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy inferred event types in 0.161.0 to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Remove the old Event and Message type arguments from <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">fromEvent</code>, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">fromEventFilterMap</code>, and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">fromEventFilterMapPreventDefault</code>. Their named config types now take <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">&lt;Target, Type, Message&gt;</code> instead of <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">&lt;Event, Message&gt;</code>. Custom event targets can declare their event maps with <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Subscription.TypedEventTarget</code>.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Subscription.aggregate</code> and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">ManagedResource.aggregate</code> also accept their records directly, inferring Model, Message, and service types. Replace <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Subscription.aggregate&lt;Model, Message&gt;()(homeSubscriptions, roomSubscriptions)</code> with <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Subscription.aggregate(homeSubscriptions, roomSubscriptions)</code>. You can still use the curried form to specify the Model and Message types explicitly.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="more-in-these-releases">More in these releases</h2><a aria-label="Copy link to More in these releases" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#more-in-these-releases" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><ul class="list-disc mb-6 space-y-2 [&amp;>li>p:last-child]:mb-0" data-foldkit-identity="408d5615f6a4615c"><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">DevTools now shows the destination path for Commands whose results reach a Submodel. For pending or interrupted Commands, the destination remains unresolved. The same information is available through DevTools MCP.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Calendar formatting follows locale-defined date order. A German locale can render <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">15. Januar 2026</code> instead of <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Januar 15, 2026</code>. Locales constructed field by field need four new format fields; the <a class="link-accent" href="https://foldkit.dev/ui/calendar#localization" data-foldkit-identity="b9c1739f4bc7044a">Calendar guide</a> covers the configuration and accessible labels.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Disclosure's <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">animatePanel</code> accepts <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">peek</code>, a CSS height for a collapsed preview. The preview stays inert and hidden from assistive technology until opened.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">A new <a class="link-accent" href="https://foldkit.dev/example-apps/livestore" data-foldkit-identity="b9c1739f4bc7044a">LiveStore example</a> synchronizes tasks across browser tabs. Writes run through Commands, and a Subscription carries query results into the Model.</p></li></ul><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Thank you to <a class="link-accent" href="https://github.com/filipfalcon" data-foldkit-identity="b9c1739f4bc7044a">@filipfalcon</a> for the Disclosure preview and Vite 8 work, and to <a class="link-accent" href="https://github.com/artile" data-foldkit-identity="b9c1739f4bc7044a">@artile</a> for the lint rule proposals included in 0.160.0!</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="upgrading">Upgrading</h2><a aria-label="Copy link to Upgrading" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#upgrading" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Pin <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">effect</code> and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">@effect/platform-browser</code> to <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">4.0.0-rc.115</code>. Foldkit requires the browser package again for page lifecycle cleanup. If you use <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">@effect/vitest</code>, its matching release requires Vitest 5; upgrade any <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">@vitest/*</code> packages together.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">@foldkit/vite-plugin</code> and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">@foldkit/markdown</code> now require Vite 8. The updated UI, DevTools, and DevTools MCP packages require Foldkit 0.161.0 or newer.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The full <a class="link-accent" href="https://github.com/foldkit/foldkit/releases/tag/foldkit%400.160.0" data-foldkit-identity="b9c1739f4bc7044a">0.160.0</a> and <a class="link-accent" href="https://github.com/foldkit/foldkit/releases/tag/foldkit%400.161.0" data-foldkit-identity="b9c1739f4bc7044a">0.161.0</a> release notes cover every package and migration detail, including changes to custom Command history records and the return value of <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Dom.showDialog</code>.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Thanks to everyone building with Foldkit!</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Devin</p></div></article>]]></content:encoded>
</item>
<item>
  <title>Foldkit 0.159.0</title>
  <link>https://foldkit.dev/blog/foldkit-0-159-0</link>
  <guid>https://foldkit.dev/blog/foldkit-0-159-0</guid>
  <description>Foldkit's Vite plugin now builds a portable Web fetch handler for Node and Workers, with smaller updates to browser input, accessibility, and tooling.</description>
  <pubDate>Sat, 12 Sep 2026 00:00:00 GMT</pubDate>
  <enclosure url="https://foldkit.dev/blog/foldkit-0-159-0/cover.webp" length="24512" type="image/webp" />
  <content:encoded><![CDATA[<article data-foldkit-identity="76a96447eaadcc72"><div class="relative overflow-hidden rounded-lg mb-8" data-foldkit-identity="80a2c6e532125e5c"><div class="absolute inset-0 bg-gray-200 dark:bg-gray-800 animate-pulse"></div><img width="3600" height="2400" class="relative w-full h-auto" src="https://foldkit.dev/blog/foldkit-0-159-0/cover.webp" alt="The number 159 in oversized lime green type cropped inside a dark browser window on a charcoal background."></div><header class="mb-8"><h1 data-pagefind-meta="section" class="font-heading font-book text-page-title md:text-page-title-wide leading-tight tracking-tight text-gray-900 dark:text-white mb-3" id="foldkit-0-159-0" data-foldkit-identity="89d40481a105ec00">Foldkit 0.159.0</h1><p class="text-gray-500 dark:text-gray-400">September 12, 2026 · Devin Jameson</p></header><div data-foldkit-identity="8fed9e3a5e2e9719"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Foldkit 0.159.0 is out. The main change is a portable <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">fetch</code> handler for server-rendered applications.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="a-portable-server-bundle">A portable server bundle</h2><a aria-label="Copy link to A portable server bundle" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#a-portable-server-bundle" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">In 0.155.0, Foldkit moved the browser build, server build, and prerendering into one <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">vite build</code>. But the server build still asked you to choose a host entry: a Node HTTP process or a custom Worker.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">@foldkit/vite-plugin</code> 0.21.0 now builds a Web <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">fetch</code> handler. The same server module can run on Node or Workers:</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#6B5CB8;--shiki-dark:#A093E2">foldkit</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">  buildId</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  ssr</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">    serverEntry</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#3D6B06;--shiki-dark:#BCDF59"> '/src/entry.server.ts'</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">    build</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#0E7490;--shiki-dark:#49CAE4"> true</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">  },</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy server build configuration to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Run <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">vite build</code> and the server output is <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">dist/server/fetch.js</code>, with a default export shaped as <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">{ fetch }</code>. A Node host serves the built client assets and passes page requests to that handler. A Worker can default-export the same module.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">This is a breaking change. Remove <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">ssr.build.entry</code> and keep <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">ssr.serverEntry</code>. Vite no longer builds your Node host. Use the <a class="link-accent" href="https://github.com/foldkit/foldkit/blob/main/examples/ssr/scripts/serve.ts" data-foldkit-identity="b9c1739f4bc7044a">SSR example's <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">scripts/serve.ts</code></a> as a reference, and start it with <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">node scripts/serve.ts</code> instead of <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">node dist/server/main.js</code>. Hosts importing <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">dist/server/entry.server.js</code> should import <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">dist/server/fetch.js</code>, which still exports <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">renderPage</code>.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The <a class="link-accent" href="https://foldkit.dev/core/server-rendering" data-foldkit-identity="b9c1739f4bc7044a">server rendering guide</a> covers the build and host setup. New SSR projects from <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">create-foldkit-app</code> also pin <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">@effect/platform-node-shared</code> to their Effect version, so a fresh install cannot silently pick up an incompatible newer prerelease.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="more-in-this-release">More in this release</h2><a aria-label="Copy link to More in this release" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#more-in-this-release" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">There are also several smaller updates:</p><ul class="list-disc mb-6 space-y-2 [&amp;>li>p:last-child]:mb-0" data-foldkit-identity="408d5615f6a4615c"><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">OnInput</code> and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">OnChange</code> support contenteditable hosts, with new <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">beforeinput</code> handlers and Scene steps for editor interactions.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">OnKeyDownSelf</code> and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">OnKeyDownSelfPreventDefault</code> ignore key events that bubble up from children.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">CustomElement events decode their payloads against the declared Schema before dispatching a Message.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Domain and Route unions gain <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">matchOrElse</code> for handling selected variants with a shared fallback.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Canceling a file picker inside a Dialog now keeps the Dialog open.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Dialog and form controls now require an explicit opt-in for <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">aria-describedby</code>.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Runtime.embed</code> reports startup failures in the console.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The DevTools MCP bin and oxlint plugin have smaller bundles built with Rolldown.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The Model preservation API uses live reload terminology, including the renamed <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">foldkit/model-preservation</code> import.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">A new <a class="link-accent" href="https://foldkit.dev/patterns/anti-patterns" data-foldkit-identity="b9c1739f4bc7044a">anti-patterns guide</a> covers common Foldkit mistakes and what to do instead.</p></li></ul><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The <a class="link-accent" href="https://github.com/foldkit/foldkit/releases/tag/foldkit%400.159.0" data-foldkit-identity="b9c1739f4bc7044a">0.159.0 release notes</a> have more context and the migration steps for the breaking changes.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Thank you to <a class="link-accent" href="https://github.com/filipfalcon" data-foldkit-identity="b9c1739f4bc7044a">@filipfalcon</a> for the portable server bundle, the Rolldown migration, and documentation improvements. Thank you also to <a class="link-accent" href="https://github.com/artile" data-foldkit-identity="b9c1739f4bc7044a">@artile</a> for correcting the documentation snippets and UI overview, and to <a class="link-accent" href="https://github.com/armancharan" data-foldkit-identity="b9c1739f4bc7044a">@armancharan</a> for the <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Runtime.embed</code> startup reporting fix!</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Thanks to everyone building with Foldkit!</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Devin</p></div></article>]]></content:encoded>
</item>
<item>
  <title>Foldkit 0.158.0</title>
  <link>https://foldkit.dev/blog/foldkit-0-158-0</link>
  <guid>https://foldkit.dev/blog/foldkit-0-158-0</guid>
  <description>Machine gains shared transitions, read-only context, simpler update integration, and a guide to defining, testing, and analyzing your application's workflows.</description>
  <pubDate>Fri, 04 Sep 2026 00:00:00 GMT</pubDate>
  <enclosure url="https://foldkit.dev/blog/foldkit-0-158-0/cover.webp" length="54872" type="image/webp" />
  <content:encoded><![CDATA[<article data-foldkit-identity="76a96447eaadcc72"><div class="relative overflow-hidden rounded-lg mb-8" data-foldkit-identity="80a2c6e532125e5c"><div class="absolute inset-0 bg-gray-200 dark:bg-gray-800 animate-pulse"></div><img width="3600" height="2400" class="relative w-full h-auto" src="https://foldkit.dev/blog/foldkit-0-158-0/cover.webp" alt="Oversized rows of the word machine cropped against a black background, with one row in lime green and the others in light gray."></div><header class="mb-8"><h1 data-pagefind-meta="section" class="font-heading font-book text-page-title md:text-page-title-wide leading-tight tracking-tight text-gray-900 dark:text-white mb-3" id="foldkit-0-158-0" data-foldkit-identity="89d40481a105ec00">Foldkit 0.158.0</h1><p class="text-gray-500 dark:text-gray-400">September 4, 2026 · Devin Jameson</p></header><div data-foldkit-identity="8fed9e3a5e2e9719"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Foldkit 0.158.0 is out. This release focuses on Machine, Foldkit's experimental API for modeling workflows as typed transition tables.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Imagine a checkout where <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">ClickedContinue</code> moves Cart to Shipping, Shipping to Payment, and Payment to Review. A Machine collects those rules in one table so you can read the allowed transitions together, test them, and generate a diagram from the same definition.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Machine has been available for a while. This release makes it easier to use inside an application, and the new <a class="link-accent" href="https://foldkit.dev/core/machine" data-foldkit-identity="b9c1739f4bc7044a">Machine guide</a> covers when to reach for it, how to integrate it, and how to keep a larger flow readable. It still ships from <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">foldkit/experimental</code> while the API settles.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="edges-return-update-records">Edges return update records</h2><a aria-label="Copy link to Edges return update records" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#edges-return-update-records" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">A Machine Edge now returns the same shape as update: <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">{ model }</code>, with <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">commands</code> when it has work to run.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Previously, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">to</code> and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">when</code> took a state builder and a separate Commands callback. In this example, both callbacks build the same order:</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Before:</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#6B5CB8;--shiki-dark:#A093E2">to</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span></span>
<span class="line"><span style="color:#3D6B06;--shiki-dark:#BCDF59">  'Placing'</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">  ({</span><span style="color:#885A06;--shiki-dark:#FFCA58"> state</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> })</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#885A06;--shiki-dark:#FFCA58"> CheckoutState</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">Placing</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> order</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#6B5CB8;--shiki-dark:#A093E2"> orderFromReview</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#885A06;--shiki-dark:#FFCA58">state</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">) </span><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">  ({</span><span style="color:#885A06;--shiki-dark:#FFCA58"> state</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> })</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> [</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">PlaceOrder</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> order</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#6B5CB8;--shiki-dark:#A093E2"> orderFromReview</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#885A06;--shiki-dark:#FFCA58">state</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">) </span><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)]</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy Machine Edge before 0.158.0 to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">After:</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#6B5CB8;--shiki-dark:#A093E2">to</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#3D6B06;--shiki-dark:#BCDF59">'Placing'</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> ({</span><span style="color:#885A06;--shiki-dark:#FFCA58"> state</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> })</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span></span>
<span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">  const</span><span style="color:#885A06;--shiki-dark:#FFCA58"> nextOrder</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> =</span><span style="color:#6B5CB8;--shiki-dark:#A093E2"> orderFromReview</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#885A06;--shiki-dark:#FFCA58">state</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">  return</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">    model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> CheckoutState</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">Placing</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> order</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> nextOrder</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> }</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">    commands</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> [</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">PlaceOrder</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> order</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> nextOrder</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> }</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)]</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">  }</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy Machine Edge in 0.158.0 to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The handler derives the order once and uses it for both the next state and the Command. The Command still executes through the Runtime after update returns.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">This is a breaking change. Wrap existing state returns in <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">{ model }</code>, and move any separate Commands callback into the same handler's <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">commands</code> field.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Thank you to <a class="link-accent" href="https://github.com/hdoro" data-foldkit-identity="b9c1739f4bc7044a">@hdoro</a> for suggesting that Machine Edges return Model and Commands together!</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="shared-transitions">Shared transitions</h2><a aria-label="Copy link to Shared transitions" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#shared-transitions" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">A checkout may allow cancellation from Cart, Shipping, Payment, and Review. Repeating that Edge under every state makes it harder to see which transitions actually differ.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Machine.forStates(...).on(...)</code> now lets you declare the cancellation once in the Machine's <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">shared</code> array:</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#6B5CB8;--shiki-dark:#A093E2">shared</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> [</span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">  Machine</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">forStates</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">([</span><span style="color:#3D6B06;--shiki-dark:#BCDF59">'Cart'</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#3D6B06;--shiki-dark:#BCDF59"> 'Shipping'</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#3D6B06;--shiki-dark:#BCDF59"> 'Payment'</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#3D6B06;--shiki-dark:#BCDF59"> 'Review'</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">])</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">on</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">    ClickedCancel</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#6B5CB8;--shiki-dark:#A093E2"> to</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#3D6B06;--shiki-dark:#BCDF59">'Cancelled'</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> ({</span><span style="color:#885A06;--shiki-dark:#FFCA58"> state</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> })</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> (</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">      model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> CheckoutState</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">Cancelled</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">        isShippingRequired</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> state</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">isShippingRequired</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">      }</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">    }</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">))</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">  }</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">]</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy shared checkout cancellation to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The handler's <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">state</code> narrows to the selected variants, so it can read their common fields. A state-local transition overrides the shared default for the same Message. Overlapping shared declarations throw when the Machine is defined.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Shared transitions also appear in the Machine's graph analysis and Mermaid output.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="folding-a-machine-into-update">Folding a Machine into update</h2><a aria-label="Copy link to Folding a Machine into update" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#folding-a-machine-into-update" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Machine.fold</code> handles the work of reading a Machine state from the enclosing Model, running a transition, writing the next state back, and returning its Commands:</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">const</span><span style="color:#885A06;--shiki-dark:#FFCA58"> foldCheckout</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> =</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Machine</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">fold</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  machine</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> checkoutMachine</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#6B5CB8;--shiki-dark:#A093E2">  read</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> (</span><span style="color:#885A06;--shiki-dark:#FFCA58">model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#0E7490;--shiki-dark:#49CAE4"> Model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">)</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#885A06;--shiki-dark:#FFCA58"> Option</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">some</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#885A06;--shiki-dark:#FFCA58">model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">checkout)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#6B5CB8;--shiki-dark:#A093E2">  write</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> (</span><span style="color:#885A06;--shiki-dark:#FFCA58">model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#885A06;--shiki-dark:#FFCA58"> nextCheckout</span><span style="color:#625E75;--shiki-dark:#9E9BAA">)</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#6B5CB8;--shiki-dark:#A093E2"> evo</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#885A06;--shiki-dark:#FFCA58">model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span><span style="color:#6B5CB8;--shiki-dark:#A093E2"> checkout</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> ()</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#885A06;--shiki-dark:#FFCA58"> nextCheckout</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> }</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy folding checkout into the application Model to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Call <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">foldCheckout(model, message)</code> from update, or use <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">foldCheckout(message)</code> as a Step in <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Update.combine</code>. If the Machine exists only in some Model variants, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">read</code> can return <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Option.none()</code> elsewhere and the fold leaves the Model unchanged.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Machines can also declare a Schema for read-only context. For example, a checkout guard can consult current inventory held elsewhere in the Model without copying it into every checkout state. <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Machine.fold</code> reads that context from the enclosing Model for each transition. Direct calls to <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">transition</code> and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">step</code> must supply it too.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="ignored-messages">Ignored Messages</h2><a aria-label="Copy link to Ignored Messages" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#ignored-messages" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Machine.step</code> now explains why a Message produced no transition:</p><ul class="list-disc mb-6 space-y-2 [&amp;>li>p:last-child]:mb-0" data-foldkit-identity="408d5615f6a4615c"><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">OutOfAlphabet</code>: the Message tag appears nowhere in the table.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">NotApplicable</code>: the table knows the Message, but the current state has no Edge for it.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">GuardsFellThrough</code>: every guard declined and there was no fallback.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">ExplicitlyIgnored</code>: evaluation reached the new <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">ignore()</code> fallback.</p></li></ul><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Use <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">ignore()</code> at the end of a guard list when doing nothing is intentional. Tests and inspectors can distinguish that decision from guards that fell through without a fallback. Static analysis also reports Edges after <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">ignore()</code> as dead transitions.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">If you construct or assert an <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Ignored</code> result, add its required <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">reason</code> field. Exhaustive matches over <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">GuardedEdge</code>, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">IgnoredReason</code>, and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">DeadTransitionReason</code> also need to handle the new ignore cases.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="more-in-this-release">More in this release</h2><a aria-label="Copy link to More in this release" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#more-in-this-release" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><ul class="list-disc mb-6 space-y-2 [&amp;>li>p:last-child]:mb-0" data-foldkit-identity="408d5615f6a4615c"><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Machine.define</code> accepts nested state unions without throwing at module load.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Reachability analysis now excludes Edges shadowed by an earlier <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">otherwise</code>, and dead-transition reports list each Edge once.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Machine.StateTransitions</code> preserves state and Message narrowing when you extract a state's transition entry into a named binding.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The docs have larger text, more space between sections, Inter for body text, and Paper Mono for code. Search is also available from the landing page.</p></li></ul><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The <a class="link-accent" href="https://foldkit.dev/core/machine" data-foldkit-identity="b9c1739f4bc7044a">Machine guide</a> walks through guards, context, shared transitions, update integration, graph analysis, and pure tests. The <a class="link-accent" href="https://foldkit.dev/example-apps/state-machine" data-foldkit-identity="b9c1739f4bc7044a">state machine example</a> lets you step through a checkout and inspect its transitions as you go.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The full <a class="link-accent" href="https://github.com/foldkit/foldkit/releases/tag/foldkit%400.158.0" data-foldkit-identity="b9c1739f4bc7044a">0.158.0 release notes</a> cover every package and migration detail.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Thanks to everyone building with Foldkit!</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Devin</p></div></article>]]></content:encoded>
</item>
<item>
  <title>Foldkit 0.156.0 and 0.157.0</title>
  <link>https://foldkit.dev/blog/foldkit-0-157-0</link>
  <guid>https://foldkit.dev/blog/foldkit-0-157-0</guid>
  <description>Two new recommended @foldkit/oxlint-plugin rules, less boilerplate when matching refined unions, plus updates to Story, Scene, Mount, @foldkit/ui, and Foldkit's Vite plugin.</description>
  <pubDate>Wed, 02 Sep 2026 00:00:00 GMT</pubDate>
  <enclosure url="https://foldkit.dev/blog/foldkit-0-157-0/cover.webp" length="19518" type="image/webp" />
  <content:encoded><![CDATA[<article data-foldkit-identity="76a96447eaadcc72"><div class="relative overflow-hidden rounded-lg mb-8" data-foldkit-identity="80a2c6e532125e5c"><div class="absolute inset-0 bg-gray-200 dark:bg-gray-800 animate-pulse"></div><img width="1600" height="1067" class="relative w-full h-auto" src="https://foldkit.dev/blog/foldkit-0-157-0/cover.webp" alt="The number 157 in large cyan type layered over the number 156 in coral on a light gray background."></div><header class="mb-8"><h1 data-pagefind-meta="section" class="font-heading font-book text-page-title md:text-page-title-wide leading-tight tracking-tight text-gray-900 dark:text-white mb-3" id="foldkit-0-157-0" data-foldkit-identity="89d40481a105ec00">Foldkit 0.156.0 and 0.157.0</h1><p class="text-gray-500 dark:text-gray-400">September 2, 2026 · Devin Jameson</p></header><div data-foldkit-identity="8fed9e3a5e2e9719"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Foldkit 0.157.0 and 0.156.0 are out.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">0.156.0 was a small release.</p><ul class="list-disc mb-6 space-y-2 [&amp;>li>p:last-child]:mb-0" data-foldkit-identity="408d5615f6a4615c"><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">HoverIntent now closes without the pointer grace delay when focus leaves the trigger and panel.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Parents can programmatically close HoverIntent with <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">HoverIntent.close</code>, for example after a user selects a menu item.</p></li></ul><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Now for 0.157.0. The appetizer is improved type safety in Story and Scene tests. The main dish is <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">@foldkit/oxlint-plugin</code> updates, with a side of more ergonomic OutMessage matching.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="better-foldkit-linting">Better Foldkit linting</h2><a aria-label="Copy link to Better Foldkit linting" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#better-foldkit-linting" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The recommended <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">@foldkit/oxlint-plugin</code> preset gained two rules.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">foldkit/no-impure-call-at-decision-time</code> reports time and randomness calls made while update is deciding which Commands to return, instead of when those Commands execute.</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">const</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Save</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> =</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Command</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">define</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#3D6B06;--shiki-dark:#BCDF59">'Save'</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  args</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> createdAt</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Schema</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">Number </span><span style="color:#625E75;--shiki-dark:#9E9BAA">},</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  messages</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> [</span><span style="color:#885A06;--shiki-dark:#FFCA58">Message</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">CompletedSave]</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#6B5CB8;--shiki-dark:#A093E2">  execute</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> ({</span><span style="color:#885A06;--shiki-dark:#FFCA58"> createdAt</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> })</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">    Effect</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">succeed</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#885A06;--shiki-dark:#FFCA58">Message</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">CompletedSave</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span><span style="color:#885A06;--shiki-dark:#FFCA58"> createdAt</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> }</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">))</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">const</span><span style="color:#6B5CB8;--shiki-dark:#A093E2"> save</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> =</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> (</span><span style="color:#885A06;--shiki-dark:#FFCA58">model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#0E7490;--shiki-dark:#49CAE4"> Model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">):</span><span style="color:#0E7490;--shiki-dark:#49CAE4"> Update</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#0E7490;--shiki-dark:#49CAE4">Return</span><span style="color:#625E75;--shiki-dark:#9E9BAA">&#x3C;</span><span style="color:#0E7490;--shiki-dark:#49CAE4">Model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#0E7490;--shiki-dark:#49CAE4"> Message</span><span style="color:#625E75;--shiki-dark:#9E9BAA">></span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> (</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">  model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#8A869C">  // Wrong: Date.now() runs while update is deciding which Commands to return.</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  commands</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> [</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">Save</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> createdAt</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Date</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">now</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">() </span><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)]</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy reading the clock while building a Command to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Move the read into the Command's Effect and return the value in its result Message:</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">const</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Save</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> =</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Command</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">define</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#3D6B06;--shiki-dark:#BCDF59">'Save'</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  messages</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> [</span><span style="color:#885A06;--shiki-dark:#FFCA58">Message</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">CompletedSave]</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#8A869C">  // Right: the clock is read only when the Command executes.</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  execute</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Clock</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#885A06;--shiki-dark:#FFCA58">currentTimeMillis</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">pipe</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">    Effect</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">map</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#885A06;--shiki-dark:#FFCA58">createdAt</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#885A06;--shiki-dark:#FFCA58"> Message</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">CompletedSave</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span><span style="color:#885A06;--shiki-dark:#FFCA58"> createdAt</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> }</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">))</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  )</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">const</span><span style="color:#6B5CB8;--shiki-dark:#A093E2"> save</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> =</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> (</span><span style="color:#885A06;--shiki-dark:#FFCA58">model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#0E7490;--shiki-dark:#49CAE4"> Model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">):</span><span style="color:#0E7490;--shiki-dark:#49CAE4"> Update</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#0E7490;--shiki-dark:#49CAE4">Return</span><span style="color:#625E75;--shiki-dark:#9E9BAA">&#x3C;</span><span style="color:#0E7490;--shiki-dark:#49CAE4">Model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#0E7490;--shiki-dark:#49CAE4"> Message</span><span style="color:#625E75;--shiki-dark:#9E9BAA">></span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> (</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">  model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  commands</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> [</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">Save</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">()]</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy reading the clock when the Command executes to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">foldkit/prefer-effect-module-names</code> reports abbreviated and trailing-underscore Effect import aliases, and auto-fixes aliases when it can identify the exported module name.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Existing applications using the preset may produce new lint errors after upgrading.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Across the preset, rules now recognize aliases for Foldkit, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">@foldkit/ui</code>, Effect, and child Message imports. They ignore local shadows and no longer mistake unrelated <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">message</code> fields for Submodel Messages.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The preset already reported parent code that constructs a child Message. In 0.157.0, the rule also catches that code when the child import is aliased. For example, a parent should not decide that opening a Dialog means dispatching its <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">RequestedOpen</code> Message:</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">const</span><span style="color:#885A06;--shiki-dark:#FFCA58"> foldDialogOpen</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> =</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Update</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">foldChildStep</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#8A869C">  // Wrong: the parent constructs one of Dialog's internal Messages.</span></span>
<span class="line"><span style="color:#6B5CB8;--shiki-dark:#A093E2">  update</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> (</span><span style="color:#885A06;--shiki-dark:#FFCA58">dialog</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#0E7490;--shiki-dark:#49CAE4"> Dialog</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#0E7490;--shiki-dark:#49CAE4">Model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">)</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">    Dialog</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">update</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#885A06;--shiki-dark:#FFCA58">dialog</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Dialog</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#885A06;--shiki-dark:#FFCA58">Message</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">RequestedOpen</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">())</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  read</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> readDialog</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  write</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> writeDialog</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  toParentMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> toGotDialogMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  foldOutMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> foldDialogOutMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy a parent constructing a Dialog Message to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Dialog exposes <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">open</code>, so the parent can fold that operation without reaching into the child's Messages. Parents should drive child behavior through update functions exposed by the child:</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">const</span><span style="color:#885A06;--shiki-dark:#FFCA58"> foldDialogOpen</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> =</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Update</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">foldChildStep</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#8A869C">  // Right: the parent calls an update function owned by Dialog.</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  update</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Dialog</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">open</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  read</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> readDialog</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  write</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> writeDialog</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  toParentMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> toGotDialogMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  foldOutMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> foldDialogOutMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy folding a child-owned update function to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">This lets the parent call a child-owned update function without depending on the child's internal Messages. <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Update.foldChildStep</code> still handles the child Model, Commands, and OutMessages. Animation in <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">@foldkit/ui</code> now exposes <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">show</code>, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">hide</code>, and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">toggle</code> update functions for the same reason.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="refined-union-matching">Refined union matching</h2><a aria-label="Copy link to Refined union matching" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#refined-union-matching" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Foldkit union matchers now accept a structurally refined union as their optional second type argument. For a Listbox whose value is refined to <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Plan</code>, this lets <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Listbox.OutMessage.match</code> keep <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">value</code> typed as <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Plan</code> without a separate Effect Match pipeline.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Before:</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#625E75;--shiki-dark:#8A869C">// Before: preserving Plan requires a separate Effect Match pipeline.</span></span>
<span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">const</span><span style="color:#885A06;--shiki-dark:#FFCA58"> foldListboxOutMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> =</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Match</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">type</span><span style="color:#625E75;--shiki-dark:#9E9BAA">&#x3C;</span><span style="color:#0E7490;--shiki-dark:#49CAE4">Listbox</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#0E7490;--shiki-dark:#49CAE4">OutMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">&#x3C;</span><span style="color:#0E7490;--shiki-dark:#49CAE4">Plan</span><span style="color:#625E75;--shiki-dark:#9E9BAA">>></span><span style="color:#403D4A;--shiki-dark:#E0DEE6">()</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">pipe</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">  Match</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">withReturnType</span><span style="color:#625E75;--shiki-dark:#9E9BAA">&#x3C;</span><span style="color:#0E7490;--shiki-dark:#49CAE4">Update</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#0E7490;--shiki-dark:#49CAE4">Step</span><span style="color:#625E75;--shiki-dark:#9E9BAA">&#x3C;</span><span style="color:#0E7490;--shiki-dark:#49CAE4">Model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#0E7490;--shiki-dark:#49CAE4"> Message</span><span style="color:#625E75;--shiki-dark:#9E9BAA">>></span><span style="color:#403D4A;--shiki-dark:#E0DEE6">()</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">  Match</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">tagsExhaustive</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">    Selected</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">      ({</span><span style="color:#885A06;--shiki-dark:#FFCA58"> value</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> })</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">      model</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> (</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#6B5CB8;--shiki-dark:#A093E2"> evo</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#885A06;--shiki-dark:#FFCA58">model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span><span style="color:#6B5CB8;--shiki-dark:#A093E2"> maybePlan</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> ()</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#885A06;--shiki-dark:#FFCA58"> Option</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">some</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#885A06;--shiki-dark:#FFCA58">value</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">) </span><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">) </span><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">  }</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy refined OutMessage fold before 0.157.0 to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">After:</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#625E75;--shiki-dark:#8A869C">// After: Foldkit's matcher preserves Plan directly.</span></span>
<span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">const</span><span style="color:#885A06;--shiki-dark:#FFCA58"> foldListboxOutMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> =</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Listbox</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#885A06;--shiki-dark:#FFCA58">OutMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">match</span><span style="color:#625E75;--shiki-dark:#9E9BAA">&#x3C;</span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">  Update</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">Step</span><span style="color:#625E75;--shiki-dark:#9E9BAA">&#x3C;</span><span style="color:#885A06;--shiki-dark:#FFCA58">Model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Message</span><span style="color:#625E75;--shiki-dark:#9E9BAA">>,</span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">  Listbox</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">OutMessage</span><span style="color:#625E75;--shiki-dark:#9E9BAA">&#x3C;</span><span style="color:#885A06;--shiki-dark:#FFCA58">Plan</span><span style="color:#625E75;--shiki-dark:#9E9BAA">></span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">></span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  Selected</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">    ({</span><span style="color:#885A06;--shiki-dark:#FFCA58"> value</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> })</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">    model</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> (</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#6B5CB8;--shiki-dark:#A093E2"> evo</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#885A06;--shiki-dark:#FFCA58">model</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span><span style="color:#6B5CB8;--shiki-dark:#A093E2"> maybePlan</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> ()</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#885A06;--shiki-dark:#FFCA58"> Option</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">some</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#885A06;--shiki-dark:#FFCA58">value</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">) </span><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">) </span><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy refined OutMessage fold in 0.157.0 to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The new form is shorter, remains exhaustive, and keeps <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">value</code> typed as <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Plan</code> in the <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Selected</code> handler.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Other changes:</p><ul class="list-disc mb-6 space-y-2 [&amp;>li>p:last-child]:mb-0" data-foldkit-identity="408d5615f6a4615c"><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Story and Scene now type-check Message and OutMessage steps against the update under test, with a new <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Story.steps</code> API for reusable Story sequences.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Mounts can use the new <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">viewStateChanges</code> Stream to stop DOM interaction while DevTools shows a historical view.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Textarea content must now use <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">h.Value</code>.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Machine.unreachableStates</code> and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Machine.deadTransitions</code> can now account for states entered through persistence or deep links.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Dialog now falls back to the first focusable element—or the dialog itself—when its requested focus target is missing or cannot receive focus.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">DevTools overlay dependencies are now preloaded, so Vite does not reload on first use.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The former Manifesto page is now <a class="link-accent" href="https://foldkit.dev/introduction/why-foldkit" data-foldkit-identity="b9c1739f4bc7044a">Why Foldkit</a>.</p></li></ul><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Thank you to <a class="link-accent" href="https://github.com/rjdellecese" data-foldkit-identity="b9c1739f4bc7044a">@rjdellecese</a> for proposing the Effect module naming convention and Mount view-state API, and to <a class="link-accent" href="https://github.com/artile" data-foldkit-identity="b9c1739f4bc7044a">@artile</a> for reporting the Dialog focus issue. Thank you also to <a class="link-accent" href="https://github.com/armancharan" data-foldkit-identity="b9c1739f4bc7044a">@armancharan</a> for adding <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">vitest.config.ts</code> typechecking across the repo and <a class="link-accent" href="https://github.com/filipfalcon" data-foldkit-identity="b9c1739f4bc7044a">@filipfalcon</a> for the Vite preload fix!</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The full <a class="link-accent" href="https://github.com/foldkit/foldkit/releases/tag/foldkit%400.156.0" data-foldkit-identity="b9c1739f4bc7044a">0.156.0</a> and <a class="link-accent" href="https://github.com/foldkit/foldkit/releases/tag/foldkit%400.157.0" data-foldkit-identity="b9c1739f4bc7044a">0.157.0</a> release notes cover every package and migration detail.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Thanks to everyone building with Foldkit!</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Devin</p></div></article>]]></content:encoded>
</item>
<item>
  <title>Foldkit 0.154.0 and 0.155.0</title>
  <link>https://foldkit.dev/blog/foldkit-0-155-0</link>
  <guid>https://foldkit.dev/blog/foldkit-0-155-0</guid>
  <description>Foldkit 0.154.0 and 0.155.0 expand click and focus controls, unify Vite builds for server-rendered apps, introduce HoverIntent, and more.</description>
  <pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate>
  <enclosure url="https://foldkit.dev/blog/foldkit-0-155-0/cover.webp" length="52494" type="image/webp" />
  <content:encoded><![CDATA[<article data-foldkit-identity="76a96447eaadcc72"><div class="relative overflow-hidden rounded-lg mb-8" data-foldkit-identity="80a2c6e532125e5c"><div class="absolute inset-0 bg-gray-200 dark:bg-gray-800 animate-pulse"></div><img width="1600" height="1067" class="relative w-full h-auto" src="https://foldkit.dev/blog/foldkit-0-155-0/cover.webp" alt="The version numbers 0.154.0 and 0.155.0 in large black type over layered translucent zeros on a lime-green background."></div><header class="mb-8"><h1 data-pagefind-meta="section" class="font-heading font-book text-page-title md:text-page-title-wide leading-tight tracking-tight text-gray-900 dark:text-white mb-3" id="foldkit-0-155-0" data-foldkit-identity="89d40481a105ec00">Foldkit 0.154.0 and 0.155.0</h1><p class="text-gray-500 dark:text-gray-400">August 29, 2026 · Devin Jameson</p></header><div data-foldkit-identity="8fed9e3a5e2e9719"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Foldkit 0.155.0 is out. I never announced 0.154.0, so this post covers both.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="what-shipped-in-0-154-0">What shipped in 0.154.0</h2><a aria-label="Copy link to What shipped in 0.154.0" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#what-shipped-in-0-154-0" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">0.154.0 shipped earlier this week with several additions worth calling out:</p><ul class="list-disc mb-6 space-y-2 [&amp;>li>p:last-child]:mb-0" data-foldkit-identity="408d5615f6a4615c"><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">h.OnClick</code> gained <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">defaultAction</code>, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">propagation</code>, and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">focusSelector</code> controls. Foldkit applies them synchronously before dispatching the Message, covering browser behavior such as preventing a default action, stopping DOM propagation, and focusing an existing element inside the originating gesture. <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">h.OnClickFocus</code> was deprecated in 0.154.0 and is removed in 0.155.0. Thank you to <a class="link-accent" href="https://github.com/hdoro" data-foldkit-identity="b9c1739f4bc7044a">@hdoro</a> for pointing out the limitation in <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">h.OnClick</code>!</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">h.OnFocusEnter</code> and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">h.OnFocusLeave</code> model focus across a compound region. Put them on a common ancestor and Foldkit dispatches only when focus crosses that boundary, not when it moves between descendants.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Update.foldChild</code> and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Update.foldChildStep</code> can now emit a derived parent OutMessage from <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">foldOutMessage</code>. A child fact can update the current Submodel and produce a different fact for its parent without making the parent Message handler inspect the child Message again.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Popover now supplies a headless <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">arrow</code> attribute bundle and keeps it positioned as the panel flips and shifts. You draw the arrow; Foldkit publishes the placement and offsets. Thank you to <a class="link-accent" href="https://github.com/foldkit/foldkit/pull/1125" data-foldkit-identity="b9c1739f4bc7044a">@wmaurer</a> for contributing it!</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">@foldkit/oxlint-plugin</code> gained <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">foldkit/no-empty-to-parent-out-message</code>, which catches <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">toParentOutMessage</code> mappers that always return <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">undefined</code> and should be omitted.</p></li></ul><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Now for 0.155.0.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="one-vite-build-for-the-whole-application">One Vite build for the whole application</h2><a aria-label="Copy link to One Vite build for the whole application" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#one-vite-build-for-the-whole-application" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Foldkit gained <a class="link-accent" href="https://foldkit.dev/blog/foldkit-has-server-rendering" data-foldkit-identity="b9c1739f4bc7044a">server rendering</a> two weeks ago. It worked, but building a server-rendered application still happened across three commands: build the browser bundle, build the server bundle, then prerender the configured routes.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">That separation mattered as soon as another Vite plugin needed to participate in the build. A deployment adapter or host plugin could join the browser build and never see the server build that followed in a separate process. It could deploy half an application. The browser and server builds could also mint different build ids, producing HTML that hydration correctly refused.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">@foldkit/vite-plugin</code> 0.20.0 now owns the whole build:</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#6B5CB8;--shiki-dark:#A093E2">foldkit</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">  buildId</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  ssr</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">    serverEntry</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#3D6B06;--shiki-dark:#BCDF59"> '/src/entry.server.ts'</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">    build</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> prerender</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#0E7490;--shiki-dark:#49CAE4"> true</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> },</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">  },</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy Vite build configuration to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Run <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">vite build</code> once. Vite produces the browser bundle, the server bundle, and, when <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">prerender</code> is enabled, a page for every path exported by the server entry. Every environment belongs to the same build and shares the same build id.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The build also writes <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">foldkit.build.json</code> beside the server bundle. It records the output directories, server entry, and generated paths so a deployment host can derive its routing behavior from the artifact instead of asking you to repeat it in platform settings.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Applications without <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">ssr.build</code> still produce a browser bundle exactly as before.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">This work came from <a class="link-accent" href="https://github.com/foldkit/foldkit/pull/1174" data-foldkit-identity="b9c1739f4bc7044a">@filipfalcon</a>. Thank you!</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="mount-construction-is-pure-now">Mount construction is pure now</h2><a aria-label="Copy link to Mount construction is pure now" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#mount-construction-is-pure-now" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Mount.define</code> and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Mount.defineStream</code> used to take positional inputs, then accept their work in a second call. A Mount with args had a curried <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">args =&gt; element =&gt; Effect&lt;Message&gt;</code> body.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">It looked compact, but it hid a bad boundary: the outer function ran when view constructed the MountAction. Anything written between those arrows ran during a pure view, on every render, rather than when the element entered the DOM.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Mount definitions now use one config object with named <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">args</code>, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">messages</code>, and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">execute</code> fields:</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Before:</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">const</span><span style="color:#885A06;--shiki-dark:#FFCA58"> AnchorPopover</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> =</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Mount</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">define</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span></span>
<span class="line"><span style="color:#3D6B06;--shiki-dark:#BCDF59">  'AnchorPopover'</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">  {</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> buttonId</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Schema</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">String</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> anchor</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> AnchorConfig</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> },</span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">  CompletedAnchorPopover</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">)(</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">  ({</span><span style="color:#885A06;--shiki-dark:#FFCA58"> buttonId</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#885A06;--shiki-dark:#FFCA58"> anchor</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> })</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">    element</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">      Effect</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">gen</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#B83530;--shiki-dark:#FF7272">function*</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> ()</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#8A869C">        // ...</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">      }</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy Mount definition before 0.155.0 to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">After:</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">const</span><span style="color:#885A06;--shiki-dark:#FFCA58"> AnchorPopover</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> =</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Mount</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">define</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#3D6B06;--shiki-dark:#BCDF59">'AnchorPopover'</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  args</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> buttonId</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Schema</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">String</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> anchor</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#885A06;--shiki-dark:#FFCA58"> AnchorConfig</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> },</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  messages</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> [</span><span style="color:#885A06;--shiki-dark:#FFCA58">CompletedAnchorPopover</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">]</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#6B5CB8;--shiki-dark:#A093E2">  execute</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> ({</span><span style="color:#885A06;--shiki-dark:#FFCA58"> element</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#885A06;--shiki-dark:#FFCA58"> buttonId</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#885A06;--shiki-dark:#FFCA58"> anchor</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> })</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">    Effect</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">gen</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#B83530;--shiki-dark:#FF7272">function*</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> ()</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#8A869C">      // ...</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">    }</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy Mount definition in 0.155.0 to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">execute</code> has the same flat shape with or without args. Constructing a MountAction now runs nothing. The runtime calls <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">execute</code> only after the element exists.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">This is a breaking change, and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">@foldkit/ui</code> 0.155.0 now requires <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">foldkit</code> 0.155.0 because its Mount definitions use the new shape. The <a class="link-accent" href="https://foldkit.dev/core/mount" data-foldkit-identity="b9c1739f4bc7044a">Mount docs</a> have the complete migration.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Thank you to <a class="link-accent" href="https://github.com/hdoro" data-foldkit-identity="b9c1739f4bc7044a">@hdoro</a> for suggesting this API change!</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="hoverintent-joins-foldkit-ui">HoverIntent joins @foldkit/ui</h2><a aria-label="Copy link to HoverIntent joins @foldkit/ui" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#hoverintent-joins-foldkit-ui" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">@foldkit/ui</code> now includes <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">HoverIntent</code>, a headless Submodel for interactions that reveal a panel from a trigger.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">It opens after a configurable pointer delay, stays open while the pointer or focus moves between the trigger and panel, and closes after a configurable grace period. Focus opens immediately. Escape closes immediately and prevents reopening until the pointer and focus have both left.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">HoverIntent returns trigger and panel event bundles. It does not create markup, choose ARIA roles, position the panel, or style anything. A Hover Card can pair it with Anchor. A hover menu can use it to keep its items available as the pointer moves from the trigger into the panel.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The <a class="link-accent" href="https://foldkit.dev/ui/hover-intent" data-foldkit-identity="b9c1739f4bc7044a">HoverIntent docs</a> have current examples and API details.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Thank you to <a class="link-accent" href="https://github.com/foldkit/foldkit/pull/1179" data-foldkit-identity="b9c1739f4bc7044a">@SyahrulBhudiF</a> for contributing it!</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="smaller-apis-got-sharper-too">Smaller APIs got sharper too</h2><a aria-label="Copy link to Smaller APIs got sharper too" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#smaller-apis-got-sharper-too" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">There is plenty more in 0.155.0:</p><ul class="list-disc mb-6 space-y-2 [&amp;>li>p:last-child]:mb-0" data-foldkit-identity="408d5615f6a4615c"><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">FieldValidation.match</code> exhaustively matches <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">NotValidated</code>, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Validating</code>, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Valid</code>, and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Invalid</code> field states without a manual Effect Match pipeline.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">CustomElement</code> builders now accept <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">ChildAttribute</code> alongside ordinary attributes, so published Submodel attribute groups compose with them just like native HTML element builders. Thank you to <a class="link-accent" href="https://github.com/jay-zahiri" data-foldkit-identity="b9c1739f4bc7044a">@jay-zahiri</a> for noting this issue!</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Scene preserves every OutMessage emitted by one update-producing step in runtime order. Use <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">expectOutMessages</code> when a batch produces several.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The renderer does less work in its hot path by caching unchanged document metadata, writing ordinary properties directly, and skipping module scans when a VNode has no module data.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Dialog now releases its resources when <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">ShowDialog</code> fails or is interrupted, and when <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">CloseDialog</code> finds that the element is already gone. Thank you to <a class="link-accent" href="https://github.com/foldkit/foldkit/pull/1191" data-foldkit-identity="b9c1739f4bc7044a">@wmaurer</a> for the fixes!</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">ManagedResource now clears its reference and dispatches its release Message when the user-provided release effect fails.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The deprecated <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">h.OnClickFocus</code> is gone. Use <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">h.OnClick(message, { focusSelector })</code>.</p></li></ul><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The packages now build and test with TypeScript 7 as well. The full <a class="link-accent" href="https://github.com/foldkit/foldkit/releases/tag/foldkit%400.154.0" data-foldkit-identity="b9c1739f4bc7044a">0.154.0</a> and <a class="link-accent" href="https://github.com/foldkit/foldkit/releases/tag/foldkit%400.155.0" data-foldkit-identity="b9c1739f4bc7044a">0.155.0</a> release notes cover every package and migration detail.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Thanks to everyone building with Foldkit!</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Devin</p></div></article>]]></content:encoded>
</item>
<item>
  <title>Foldkit Has Server Rendering</title>
  <link>https://foldkit.dev/blog/foldkit-has-server-rendering</link>
  <guid>https://foldkit.dev/blog/foldkit-has-server-rendering</guid>
  <description>Your Foldkit application can now render to HTML at build time or per request, then hydrate on the client.</description>
  <pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate>
  <enclosure url="https://foldkit.dev/blog/foldkit-has-server-rendering/cover.webp" length="25924" type="image/webp" />
  <content:encoded><![CDATA[<article data-foldkit-identity="76a96447eaadcc72"><div class="relative overflow-hidden rounded-lg mb-8" data-foldkit-identity="80a2c6e532125e5c"><div class="absolute inset-0 bg-gray-200 dark:bg-gray-800 animate-pulse"></div><img width="1600" height="1066" class="relative w-full h-auto" src="https://foldkit.dev/blog/foldkit-has-server-rendering/cover.webp" alt="The letters SSR in cyan set over a large black circle on a coral background."></div><header class="mb-8"><h1 data-pagefind-meta="section" class="font-heading font-book text-page-title md:text-page-title-wide leading-tight tracking-tight text-gray-900 dark:text-white mb-3" id="foldkit-has-server-rendering" data-foldkit-identity="89d40481a105ec00">Foldkit Has Server Rendering</h1><p class="text-gray-500 dark:text-gray-400">August 15, 2026 · Devin Jameson</p></header><div data-foldkit-identity="8fed9e3a5e2e9719"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Until today, Foldkit was purely an SPA framework. The server sent an HTML file to the client, the client requested the JavaScript bundle, and once it loaded, the application booted.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">There are issues with this approach in isolation:</p><ul class="list-disc mb-6 space-y-2 [&amp;>li>p:last-child]:mb-0" data-foldkit-identity="408d5615f6a4615c"><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The user sees the server's HTML before the JavaScript loads. Unless you prerender HTML that matches the loaded app, that is typically a blank page.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">There is no first-class way to do SSG. The workaround is a heavy prerender step: for example, using Playwright to visit each route and capture HTML (which the Foldkit website used to do).</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">There is no first-class way to do request-time SSR: for example, the server sending the client an initial HTML file personalized to the logged-in user.</p></li></ul><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">There was one more problem. Foldkit not having SSR was the deal-breaker for <a class="link-accent" href="https://x.com/MichaelArnaldi" data-foldkit-identity="b9c1739f4bc7044a">Michael Arnaldi</a>, BDFL of Effect. And that simply will not do.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><a class="link-accent" href="https://x.com/MichaelArnaldi/status/2059527426833592755" data-foldkit-identity="b9c1739f4bc7044a"><img class="max-w-full" src="https://foldkit.dev/blog/foldkit-has-server-rendering/michael-ssr-dealbreaker.webp" alt="Michael Arnaldi on X: &quot;Personally it's the deal breaker for me, I can't see myself writing 500+ lines of code to do SSG and not have a solution for SSR. I think we made the same mistakes over and over again, server side rendering is strictly necessary for good DX. I like the rest of the design.&quot;" data-foldkit-identity="0d4c8508e5bd39bb"></a></p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">So, Foldkit can render on the server now. It shipped today under <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">foldkit/experimental/server</code>. It will be promoted to <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">foldkit/server</code> once the community puts it through its paces.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">foldkit/experimental/server</code> ships <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">renderToString</code>, and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">foldkit/runtime</code> ships <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">hydrate</code>. Together, they give a Foldkit application two new ways to reach the browser: generate static HTML for selected routes during the build, or render each request on a server. When the server and client agree, the browser adopts the served HTML in place. A mismatched subtree is rebuilt, and an invalid or cross-deployment handoff is refused. The application that boots is the same Foldkit application you wrote yesterday.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">A Foldkit app can remain a pure client-side SPA. Server rendering is opt-in.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="ssg-vs-ssr">SSG vs SSR</h2><a aria-label="Copy link to SSG vs SSR" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#ssg-vs-ssr" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">SSG and SSR are the same thing run at different times. Either a build script calls your server entry once per URL and writes files, or a server calls it once per request and sends the response. The entry is a small module that derives flags from a <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Request</code> and asks Foldkit to render:</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">import</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Effect</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> }</span><span style="color:#B83530;--shiki-dark:#FF7272"> from</span><span style="color:#3D6B06;--shiki-dark:#BCDF59"> 'effect'</span></span>
<span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">import</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Server</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> }</span><span style="color:#B83530;--shiki-dark:#FF7272"> from</span><span style="color:#3D6B06;--shiki-dark:#BCDF59"> 'foldkit/experimental'</span></span>
<span class="line"></span>
<span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">import</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span><span style="color:#885A06;--shiki-dark:#FFCA58"> readCountCookie</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> }</span><span style="color:#B83530;--shiki-dark:#FF7272"> from</span><span style="color:#3D6B06;--shiki-dark:#BCDF59"> './cookie'</span></span>
<span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">import</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Flags</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#885A06;--shiki-dark:#FFCA58"> init</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#885A06;--shiki-dark:#FFCA58"> view</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> }</span><span style="color:#B83530;--shiki-dark:#FF7272"> from</span><span style="color:#3D6B06;--shiki-dark:#BCDF59"> './main'</span></span>
<span class="line"></span>
<span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">const</span><span style="color:#6B5CB8;--shiki-dark:#A093E2"> flagsForRequest</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> =</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> (</span><span style="color:#885A06;--shiki-dark:#FFCA58">request</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#0E7490;--shiki-dark:#49CAE4"> Request</span><span style="color:#625E75;--shiki-dark:#9E9BAA">):</span><span style="color:#0E7490;--shiki-dark:#49CAE4"> Flags</span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span><span style="color:#403D4A;--shiki-dark:#E0DEE6"> (</span><span style="color:#625E75;--shiki-dark:#9E9BAA">{</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  initialCount</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#6B5CB8;--shiki-dark:#A093E2"> readCountCookie</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#885A06;--shiki-dark:#FFCA58">request</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#885A06;--shiki-dark:#FFCA58">headers</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">get</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#3D6B06;--shiki-dark:#BCDF59">'cookie'</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">) </span><span style="color:#625E75;--shiki-dark:#9E9BAA">??</span><span style="color:#3D6B06;--shiki-dark:#BCDF59"> ''</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">}</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">export</span><span style="color:#B83530;--shiki-dark:#FF7272"> const</span><span style="color:#6B5CB8;--shiki-dark:#A093E2"> renderPage</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> =</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> (</span><span style="color:#885A06;--shiki-dark:#FFCA58">request</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#0E7490;--shiki-dark:#49CAE4"> Request</span><span style="color:#625E75;--shiki-dark:#9E9BAA">):</span><span style="color:#0E7490;--shiki-dark:#49CAE4"> Promise</span><span style="color:#625E75;--shiki-dark:#9E9BAA">&#x3C;</span><span style="color:#0E7490;--shiki-dark:#49CAE4">Server</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#0E7490;--shiki-dark:#49CAE4">EntryResult</span><span style="color:#625E75;--shiki-dark:#9E9BAA">></span><span style="color:#B83530;--shiki-dark:#FF7272"> =></span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">  Effect</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">runPromise</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span></span>
<span class="line"><span style="color:#885A06;--shiki-dark:#FFCA58">    Effect</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">gen</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#B83530;--shiki-dark:#FF7272">function*</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> ()</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span></span>
<span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">      const</span><span style="color:#885A06;--shiki-dark:#FFCA58"> renderedApplication</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> =</span><span style="color:#B83530;--shiki-dark:#FF7272"> yield*</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Server</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">renderToString</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">        {</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Flags</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#885A06;--shiki-dark:#FFCA58"> init</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#885A06;--shiki-dark:#FFCA58"> view</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> },</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">        {</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">          flags</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#6B5CB8;--shiki-dark:#A093E2"> flagsForRequest</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#885A06;--shiki-dark:#FFCA58">request</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">          buildId</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#B83530;--shiki-dark:#FF7272"> import</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">meta</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#885A06;--shiki-dark:#FFCA58">env</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#885A06;--shiki-dark:#FFCA58">FOLDKIT_BUILD_ID</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">        },</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">      )</span></span>
<span class="line"></span>
<span class="line"><span style="color:#B83530;--shiki-dark:#FF7272">      return</span><span style="color:#885A06;--shiki-dark:#FFCA58"> Server</span><span style="color:#625E75;--shiki-dark:#9E9BAA">.</span><span style="color:#6B5CB8;--shiki-dark:#A093E2">Rendered</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">(</span><span style="color:#885A06;--shiki-dark:#FFCA58">renderedApplication</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">        headers</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#625E75;--shiki-dark:#9E9BAA"> {</span></span>
<span class="line"><span style="color:#3D6B06;--shiki-dark:#BCDF59">          'cache-control'</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#3D6B06;--shiki-dark:#BCDF59"> 'private, no-store'</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">          vary</span><span style="color:#625E75;--shiki-dark:#9E9BAA">:</span><span style="color:#3D6B06;--shiki-dark:#BCDF59"> 'cookie'</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">        },</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">      }</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span></span>
<span class="line"><span style="color:#625E75;--shiki-dark:#9E9BAA">    }</span><span style="color:#403D4A;--shiki-dark:#E0DEE6">)</span><span style="color:#625E75;--shiki-dark:#9E9BAA">,</span></span>
<span class="line"><span style="color:#403D4A;--shiki-dark:#E0DEE6">  )</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy server entry example to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Flags</code> Schema, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">init</code>, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">view</code>, and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">flagsForRequest</code> are provided by you. The rest is wiring.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">The same entry serves Vite in development, a Node host in production, a build script for static generation, and fetch-native runtimes like Cloudflare Workers. Hosts are interchangeable because the entry deals only in Web standards: a Web <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Request</code> goes in, and the host turns the result into a Web <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">Response</code>.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="how-it-works">How it works</h2><a aria-label="Copy link to How it works" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#how-it-works" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Foldkit's view is a pure function of the Model, so most of server rendering was less "add SSR to the framework" and more "call the same function somewhere else."</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">If you are using Foldkit without SSR, the browser runs the whole sequence: your <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">flags</code> Effect produces the flags, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">init</code> turns them into the first Model, and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">view</code> renders it.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">With SSR, the server runs the front of that sequence and the browser finishes it:</p><ul class="list-disc mb-6 space-y-2 [&amp;>li>p:last-child]:mb-0" data-foldkit-identity="408d5615f6a4615c"><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><strong data-foldkit-identity="53c122144cc5e287">On the server</strong>, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">flagsForRequest</code> turns the request into flags, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">init</code> builds the first Model, and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">view</code> renders it to HTML. That HTML ships to the browser with the flags serialized alongside it.</p></li><li data-foldkit-identity="54c53c1004e2635b"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><strong data-foldkit-identity="53c122144cc5e287">On the client</strong>, <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">init</code> runs again with those same flags, rebuilds the initial Model, and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">view</code> renders it. Hydration adopts matching server DOM and rebuilds a mismatched subtree from its nearest parent.</p></li></ul><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">There is no separate server-side Model to reconcile with the client's. Both sides derive the initial Model from the same flags and <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">init</code>, then render it through the same <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">view</code>.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">After hydration, the initial Commands run, and your Foldkit application behaves like a typical SPA with client-side navigation.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="what-shipped">What shipped</h2><a aria-label="Copy link to What shipped" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#what-shipped" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Check out the new docs page on <a class="link-accent" href="https://foldkit.dev/core/server-rendering" data-foldkit-identity="b9c1739f4bc7044a">Server Rendering</a>, and the runnable <a class="link-accent" href="https://foldkit.dev/example-apps/ssg" data-foldkit-identity="b9c1739f4bc7044a">Static Site Generation</a> and <a class="link-accent" href="https://foldkit.dev/example-apps/ssr" data-foldkit-identity="b9c1739f4bc7044a">Server-Side Rendering</a> examples.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">This website (<a class="link-accent" href="https://foldkit.dev" data-foldkit-identity="b9c1739f4bc7044a">foldkit.dev</a>) now prerenders every route through the same <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">renderPage</code> contract (SSG). The page you are reading hydrated in place.</p><div class="group flex items-center gap-1 md:hover-capable:gap-0 mt-16 mb-4 [h1+&amp;]:mt-12 md:hover-capable:flex-row-reverse md:hover-capable:justify-end md:hover-capable:-ml-[1.5rem]" data-foldkit-identity="caca73818d585138"><h2 class="font-heading font-book text-2xl md:text-3xl leading-snug tracking-tight text-gray-900 dark:text-white scroll-mt-6" id="what-this-means-for-foldkit">What this means for Foldkit</h2><a aria-label="Copy link to What this means for Foldkit" class="px-0.5 py-1 rounded transition-opacity text-gray-400 dark:text-gray-500 hover:text-gray-800 dark:hover:text-gray-200 focus-visible:text-gray-800 dark:focus-visible:text-gray-200 focus-visible:opacity-100 cursor-pointer hover-capable:opacity-0 hover-capable:group-hover:opacity-100" href="#what-this-means-for-foldkit" data-foldkit-identity="0e98846c7a53f64f"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="a71898c5469a9bb4"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"></path></svg></a></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Foldkit is not getting a second programming model. It is gaining a crucial capability.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">There are no server components, no <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">'use client'</code> or <code class="bg-gray-200/60 dark:bg-gray-800 text-[var(--code-foreground)] [a_&amp;]:text-inherit [:is(h1,h2,h3,h4,h5,h6)_&amp;]:text-inherit mx-[0.1em] px-[0.25em] py-[0.05em] rounded-xs text-inline-code font-code wrap-anywhere" data-foldkit-identity="1cbc8656d30d3335">'use server'</code> boundaries, and no plan for them: the view is one function of one Model. Server rendering changes where the first paint comes from, not how you write applications.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Scaffold a Foldkit SSR application:</p><div data-pagefind-ignore="" class="relative min-w-0 mt-6 mb-6" data-foldkit-identity="dc9422a13b784eb0"><div class="text-sm"><pre class="shiki shiki-themes 0x96f-light 0x96f-dark" style="background-color:#eeedf2;--shiki-dark-bg:#1c1a20;color:#403d4a;--shiki-dark:#E0DEE6" tabindex="0"><code><span class="line"><span style="color:#6B5CB8;--shiki-dark:#A093E2">npx</span><span style="color:#3D6B06;--shiki-dark:#BCDF59"> create-foldkit-app@latest</span><span style="color:#0E7490;--shiki-dark:#49CAE4"> --rendering</span><span style="color:#3D6B06;--shiki-dark:#BCDF59"> ssr</span></span></code></pre></div><div class="code-embed-copy absolute top-2 right-2" data-foldkit-identity="8da9fb08f546f30b"><span role="status" aria-live="polite" class="sr-only"></span><button aria-label="Copy create a server-rendered Foldkit project to clipboard" class="p-2 rounded transition cursor-pointer border border-gray-300 dark:border-gray-700/50 bg-[var(--code-background)] text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:border-gray-400 dark:hover:border-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700/30"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5" data-foldkit-identity="cf52cab577a864a4"><path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"></path></svg></button></div></div><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Check it out and let me know what breaks. And don't be a stranger!</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Devin</p></div></article>]]></content:encoded>
</item>
<item>
  <title>Dispatch 1</title>
  <link>https://foldkit.dev/blog/dispatch-1</link>
  <guid>https://foldkit.dev/blog/dispatch-1</guid>
  <description>APS-4 is on the fritz again.</description>
  <pubDate>Tue, 11 Aug 2026 00:00:00 GMT</pubDate>
  <enclosure url="https://foldkit.dev/blog/dispatch-1/cover.webp" length="23100" type="image/webp" />
  <content:encoded><![CDATA[<article data-foldkit-identity="76a96447eaadcc72"><div class="relative overflow-hidden rounded-lg mb-8" data-foldkit-identity="80a2c6e532125e5c"><div class="absolute inset-0 bg-gray-200 dark:bg-gray-800 animate-pulse"></div><img width="1600" height="1067" class="relative w-full h-auto" src="https://foldkit.dev/blog/dispatch-1/cover.webp" alt="Yellow and coral triangles glide toward a huge dark planet across a teal sky, past dashed flight paths and a small green moon, with bands of green, yellow, and gray along the left edge."></div><header class="mb-8"><h1 data-pagefind-meta="section" class="font-heading font-book text-page-title md:text-page-title-wide leading-tight tracking-tight text-gray-900 dark:text-white mb-3" id="dispatch-1" data-foldkit-identity="89d40481a105ec00">Dispatch 1</h1><p class="text-gray-500 dark:text-gray-400">August 11, 2026 · Devin Jameson</p></header><div data-foldkit-identity="8fed9e3a5e2e9719"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><em data-foldkit-identity="dbce66070d77e202">Beep. Beep. Beep.</em></p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">APS-4 is on the fritz again.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Time to twiddle my thumbs.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Can you really blame me?</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">I’ve done the math. My job is <em data-foldkit-identity="dbce66070d77e202">oversight</em>. Manual manipulation results in glutamate accumulation. Oversight quality suffers. The mission suffers. Therefore, I don’t do manual. QED.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Besides, I don’t pine for the good old days.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">APS-4 does the wrong thing sometimes. It doesn’t matter.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Mostly, it does what I want. It does what I <em data-foldkit-identity="dbce66070d77e202">don’t know I want</em>.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Every outage I realize how little I ever knew.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><em data-foldkit-identity="dbce66070d77e202">Beep. Beep. Beep.</em></p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Good time to check telemetry.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Day 417. 1,546 logs transmitted. 184 supply drops. 775 commendations. 9,341 recent supply requisitions. Progress unknown. Mission ambiguous. I don’t know what these numbers mean.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">I feel itchy. There’s work to be done. Reports don’t cease when lunar base servers go down.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">But I’m past the point of commanding this thing with my own two hands. Not in this asteroid field.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">APS-4 has 10,000 hands. Each hand has 10,000 fingers. Even its fingers have fingers.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">I’m not proud enough to cosplay as a billion fingers.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><em data-foldkit-identity="dbce66070d77e202">Beep. Beep. Beep.</em></p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">I do miss driving stick. I was a decent pilot.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Sometimes, when the radar is clear, I kill the uplink, just to remember what it was like. I probably hand-grind my coffee for the same reason.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">At least they haven’t made autopilot autopilot yet.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><em data-foldkit-identity="dbce66070d77e202">Beep. Beep. Beep.</em></p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">I converse with APS-4 more than I would like. It is effective and exhausting.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">I receive daily transmissions from fellow astronauts. I can make out their ships in the distance. Their messages are wonderful. They are so <em data-foldkit-identity="dbce66070d77e202">human</em>.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">In these quiet moments, I wonder if—</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50"><em data-foldkit-identity="dbce66070d77e202">We sincerely apologize for the disruption to your service. APS-4 access is restored. State your request.</em></p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">APS-4, dispatch mission log.</p></div></article>]]></content:encoded>
</item>
<item>
  <title>Foldkit Has a Blog Now</title>
  <link>https://foldkit.dev/blog/introducing-the-foldkit-blog</link>
  <guid>https://foldkit.dev/blog/introducing-the-foldkit-blog</guid>
  <description>The Foldkit blog now exists.</description>
  <pubDate>Sat, 01 Aug 2026 00:00:00 GMT</pubDate>
  <content:encoded><![CDATA[<article data-foldkit-identity="76a96447eaadcc72"><header class="mb-8"><h1 data-pagefind-meta="section" class="font-heading font-book text-page-title md:text-page-title-wide leading-tight tracking-tight text-gray-900 dark:text-white mb-3" id="introducing-the-foldkit-blog" data-foldkit-identity="89d40481a105ec00">Foldkit Has a Blog Now</h1><p class="text-gray-500 dark:text-gray-400">August 1, 2026 · Devin Jameson</p></header><div data-foldkit-identity="8fed9e3a5e2e9719"><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">Hey, Devin here. Foldkit has a blog now.</p><p class="mb-5 leading-7" data-foldkit-identity="ab595b796d113f50">This website is made with Foldkit and the blog uses <a class="link-accent" href="https://github.com/foldkit/foldkit/blob/main/packages/markdown/README.md" data-foldkit-identity="b9c1739f4bc7044a">@foldkit/markdown</a>.</p></div></article>]]></content:encoded>
</item>
</channel>
</rss>