Next page>;
+}`,
+ hono: `import { useState } from 'hono/jsx';
+import { Link } from '@void/hono';
+export default function Page({ message }: { message: string }) {
+ const [count, setCount] = useState(0);
+ return <>
{message}
Next page>;
}`,
};
diff --git a/.github/scripts/packed-init.mjs b/.github/scripts/packed-init.mjs
index 117b4e496..88592498c 100644
--- a/.github/scripts/packed-init.mjs
+++ b/.github/scripts/packed-init.mjs
@@ -122,7 +122,7 @@ export async function initializePackedProject(
version,
toolchain = 'vite',
) {
- const frameworks = ['react', 'vue', 'svelte', 'solid'];
+ const frameworks = ['react', 'vue', 'svelte', 'solid', 'hono'];
assert(frameworks.includes(framework), 'Unknown Pages framework');
assert(['npm', 'pnpm'].includes(manager), 'Unknown package manager');
assert(['vite', 'vite-plus'].includes(toolchain), 'Unknown toolchain');
diff --git a/AGENTS.md b/AGENTS.md
index 760c468ae..78e4af404 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -73,6 +73,7 @@ pnpm workspaces managed through Vite+. Shared dependency versions use the **pnpm
| [`packages/vue`](./packages/vue/README.md) | `@void/vue` | Vue framework adapter for Pages mode (SSR, Link, useForm) |
| [`packages/svelte`](./packages/svelte/README.md) | `@void/svelte` | Svelte 5 framework adapter for Pages mode (SSR, Link, useForm) |
| [`packages/solid`](./packages/solid/README.md) | `@void/solid` | SolidJS framework adapter for Pages mode (SSR, Link, useForm) |
+| [`packages/hono`](./packages/hono/README.md) | `@void/hono` | Hono JSX framework adapter for Pages mode (SSR, Link, useForm) |
| [`docs`](./docs) | (private) | Documentation site (VitePress) |
| [`platform`](./platform/README.md) | (private) | Self-hosted platform source, routing, proxy, logs, and dashboard |
| `playground/*` | (private) | local apps for testing |
@@ -85,7 +86,7 @@ Platform packages live under `platform/packages/*` and may depend on public/shar
Read [the core package instructions](./packages/void/AGENTS.md) for plugin,
runtime, code-generation and CLI invariants. Each framework adapter has its
-own README under `packages/{react,vue,svelte,solid}`.
+own README under `packages/{react,vue,svelte,solid,hono}`.
The [API reference](./docs/reference/api.md) and
[CLI reference](./docs/reference/cli.md) describe the supported public surface.
diff --git a/README.md b/README.md
index d19824294..6e693be18 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ Void brings together three open-source tools for you and your coding agents:
- **Void CLI:** Build your app, provision the Cloudflare resources it uses, apply migrations, and deploy with one command. Manage resources, inspect logs, and roll back through the same CLI.
- **Void Platform:** Install a shared deployment environment in your Cloudflare account for your team or customers, with access controls, resource limits, usage reporting, and [connected applications](./docs/guide/platform/administration/connected-apps.md) that request user-approved deployments.
-The SDK's features are optional and composable. Use React, Vue, Svelte, or Solid for Void pages, or keep a [supported application framework](https://void.cloud/integrations/frameworks/overview) for routing and rendering while Void handles resource APIs, migrations, and deployment.
+The SDK's features are optional and composable. Use React, Vue, Svelte, Solid, or Hono for Void pages, or keep a [supported application framework](https://void.cloud/integrations/frameworks/overview) for routing and rendering while Void handles resource APIs, migrations, and deployment.
## Getting Started
diff --git a/TESTING.md b/TESTING.md
index 7d9ed3435..25c136055 100644
--- a/TESTING.md
+++ b/TESTING.md
@@ -75,6 +75,7 @@ vp run test:integration
vp run test:metaframeworks
vp run test:pages:react-vue
vp run test:pages:svelte-solid
+vp run test:pages:hono
vp run test:platform
```
@@ -213,7 +214,7 @@ workspace links can hide. They do not publish packages or deploy applications.
Smoke coverage checks package contents and exports, real initialization, CLI help, a frozen
reinstall, public Vite builds, TypeScript, and development HTTP requests for pages, assets, and
-KV. It uses no browser. Full coverage adds Vue, Svelte, Solid, Markdown, production preview,
+KV. It uses no browser. Full coverage adds Vue, Svelte, Solid, Hono, Markdown, production preview,
and browser hydration/navigation. Superseded PR/main runs are cancelled; release runs are not.
The selector reads all PR file pages or the complete pushed commit range. Renames consider both
@@ -228,7 +229,7 @@ VOID_PACKED_SUITE=full node .github/scripts/packed-consumer.mjs
node --test --test-timeout=10000 .github/scripts/packed-*.test.mjs
```
-`VOID_PACKED_PM=npm|pnpm` and `VOID_PACKED_FRAMEWORK=react|vue|svelte|solid` select a focused
+`VOID_PACKED_PM=npm|pnpm` and `VOID_PACKED_FRAMEWORK=react|vue|svelte|solid|hono` select a focused
local run. `VOID_PACKED_TOOLCHAIN=vite-plus` verifies Vite+ initialization, the workspace's
tested Vite+ version, and the generated `vp` build/dev/preview commands. CI checks a React
app with Vite+ for both package managers alongside the plain Vite coverage.
diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts
index 477230ab3..bb0944e8d 100644
--- a/docs/.vitepress/config.ts
+++ b/docs/.vitepress/config.ts
@@ -183,7 +183,7 @@ export default extendConfig(
},
vite: {
- plugins: [groupIconVitePlugin()],
+ plugins: [groupIconVitePlugin({ customIcon: { hono: 'logos:hono' } })],
},
themeConfig: {
diff --git a/docs/guide/app-types.md b/docs/guide/app-types.md
index 24e91204c..189d5a225 100644
--- a/docs/guide/app-types.md
+++ b/docs/guide/app-types.md
@@ -14,7 +14,7 @@ The type is auto-detected from your project structure, or you can set it explici
## Void Apps
-In a Void app, Void handles server routing and deployment. Use React, Vue, Svelte, or Solid for server-rendered pages, or build a frontend with any library that works with Vite.
+In a Void app, Void handles server routing and deployment. Use React, Vue, Svelte, Solid, or Hono for server-rendered pages, or build a frontend with any library that works with Vite.
A Void app can be **API-only** (just `routes/`), a **SPA + API** (frontend in `src/` with API routes), or **full-stack with pages mode** (server-rendered pages in `pages/` with co-located data loading):
diff --git a/docs/guide/index.md b/docs/guide/index.md
index 82bb3a0d3..0b0cade3a 100644
--- a/docs/guide/index.md
+++ b/docs/guide/index.md
@@ -4,7 +4,7 @@ outline: deep
# What is Void?
-Void is a full-stack framework for Cloudflare Workers, powered by Vite. Build your UI with React, Vue, Svelte, or Solid, and write server code in the same project. Void connects routing, data access, and deployment while keeping types shared across your app.
+Void is a full-stack framework for Cloudflare Workers, powered by Vite. Build your UI with React, Vue, Svelte, Solid, or Hono, and write server code in the same project. Void connects routing, data access, and deployment while keeping types shared across your app.
Start with the [Quickstart](./quickstart.md) to create and deploy an app. If you already use a meta framework, follow its [integration guide](../integrations/frameworks/overview.md).
diff --git a/docs/guide/pages-routing/actions-and-forms.md b/docs/guide/pages-routing/actions-and-forms.md
index 1b12747ce..8dc34e523 100644
--- a/docs/guide/pages-routing/actions-and-forms.md
+++ b/docs/guide/pages-routing/actions-and-forms.md
@@ -141,6 +141,28 @@ export default function CreateUser() {
}
```
+```tsx [Hono]
+// pages/users/index.tsx
+import { Form, useForm } from '@void/hono';
+
+export default function CreateUser() {
+ const form = useForm('/users', { name: '', email: '' });
+ const value = (e: Event) => (e.target as HTMLInputElement).value;
+
+ return (
+
+ );
+}
+```
+
:::
The types are inferred from your action's `withValidator()` schema in the companion `.server.ts` file. If no validator is defined, the body type falls back to `Record`, and you still get URL autocomplete.
@@ -167,7 +189,7 @@ The types are inferred from your action's `withValidator()` schema in the compan
Use `setError()` for client-side validation. Editing a field clears its error automatically.
-For a native React form, use `form.post`, `form.put`, `form.patch`, or `form.delete` as a native form action. For an awaitable mutation, use `action()`. In Vue, Svelte, and Solid, form submissions return `Promise`; catch thrown errors or use your framework's error handling.
+For a native React form, use `form.post`, `form.put`, `form.patch`, or `form.delete` as a native form action. For an awaitable mutation, use `action()`. In Vue, Svelte, Solid, and Hono, form submissions return `Promise`; catch thrown errors or use your framework's error handling.
For dynamic routes, pass `params` in the options:
@@ -200,7 +222,7 @@ const form = useForm(
If a callback awaits `router.visit()` or `router.refresh()`, pass `{ resolveOn: 'data' }` so it can finish before React commits the navigation. See [React navigation completion](../../reference/api/pages.md#react-navigation-completion).
-Vue, Svelte, and Solid submissions return a promise instead; use `await form.post()` to run work after a submission.
+Vue, Svelte, Solid, and Hono submissions return a promise instead; use `await form.post()` to run work after a submission.
### Scroll after submission
@@ -216,7 +238,7 @@ await action('/users/:id?update', {
});
```
-In React, set `preserveScroll` in the third argument to `useForm()`. In Vue, Svelte, and Solid, pass it to the submit method, such as `form.post({ preserveScroll: false })`.
+In React, set `preserveScroll` in the third argument to `useForm()`. In Vue, Svelte, Solid, and Hono, pass it to the submit method, such as `form.post({ preserveScroll: false })`.
## Named Actions
@@ -277,7 +299,7 @@ Each named action has its own validator schema, which supplies types for its URL
Use `action()` for a button or other mutation that does not need form state. It updates the page after a successful request:
```ts
-import { action } from '@void/react'; // or "@void/vue", "@void/svelte", "@void/solid"
+import { action } from '@void/react'; // or "@void/vue", "@void/svelte", "@void/solid", "@void/hono"
const result = await action('/users/:id?delete', {
params: { id: '42' },
@@ -303,7 +325,7 @@ Authentication errors (`401`, `403`), server errors (`500`, `502`), and unexpect
Use `isVoidActionError()` to tell a failed action apart from other errors. It's `true` for a `VoidActionError` at any status, and narrows the error so you can read `status` and `message`. `isCallSiteActionError()` is `true` only for the expected errors that `action()` returns.
```ts
-import { isVoidActionError } from '@void/react'; // or "@void/vue", "@void/svelte", "@void/solid"
+import { isVoidActionError } from '@void/react'; // or "@void/vue", "@void/svelte", "@void/solid", "@void/hono"
function describeError(error: unknown) {
if (isVoidActionError(error)) {
@@ -410,6 +432,23 @@ export default function Upload() {
}
```
+```tsx [Hono]
+import { Form, useForm } from '@void/hono';
+
+export default function Upload() {
+ const form = useForm('/photos', { title: '', photo: null as File | null });
+ const input = (e: Event) => e.target as HTMLInputElement;
+
+ return (
+
+ );
+}
+```
+
:::
On the server, use `c.req.parseBody()` to access the uploaded file:
diff --git a/docs/guide/pages-routing/islands.md b/docs/guide/pages-routing/islands.md
index abb8a166f..dd40a8acb 100644
--- a/docs/guide/pages-routing/islands.md
+++ b/docs/guide/pages-routing/islands.md
@@ -152,6 +152,27 @@ export default function BlogIndex(props) {
}
```
+```tsx [Hono]
+// pages/blog/index.island.tsx
+import Counter from './_Counter' with { island: 'load' };
+import PostForm from './_PostForm' with { island: 'visible' };
+
+export default function BlogIndex(props) {
+ return (
+
+ );
+}
+```
+
:::
Components imported _without_ the `island` attribute are rendered as static HTML only. No JavaScript is sent to the browser for them.
@@ -342,6 +363,41 @@ export default function PostForm() {
}
```
+```tsx [Hono]
+import { useIslandForm } from '@void/hono';
+
+export default function PostForm() {
+ const form = useIslandForm({ title: '', body: '' });
+
+ return (
+
+ );
+}
+```
+
:::
`useIslandForm` provides the same form state as [`useForm`](./actions-and-forms#useform). Pass the action URL to `post`, `put`, `patch`, or `delete` to submit.
diff --git a/docs/guide/pages-routing/layouts.md b/docs/guide/pages-routing/layouts.md
index a51cb604a..d9a4ccb70 100644
--- a/docs/guide/pages-routing/layouts.md
+++ b/docs/guide/pages-routing/layouts.md
@@ -140,9 +140,29 @@ export default function Layout(props: { children: JSX.Element }) {
}
```
+```tsx [Hono]
+// pages/layout.tsx
+import { useShared, Link } from '@void/hono';
+import type { Child } from 'hono/jsx';
+
+export default function Layout(props: { children?: Child }) {
+ const shared = useShared();
+ return (
+ <>
+
+ {props.children}
+ >
+ );
+}
+```
+
:::
-When a page renders, the layout wraps it. The page component is injected as the layout's children in React, Solid, and Svelte, or as a slot in Vue:
+When a page renders, the layout wraps it. The page component is injected as the layout's children in React, Solid, Svelte, and Hono, or as a slot in Vue:
@@ -192,6 +212,14 @@ export default function Page() {
}
```
+```tsx [Hono]
+export const layout = 'landing';
+
+export default function Page() {
+ return
This page uses the landing layout
;
+}
+```
+
:::
For markdown pages, use frontmatter:
diff --git a/docs/guide/pages-routing/loaders.md b/docs/guide/pages-routing/loaders.md
index 39cfd43d1..466d6609f 100644
--- a/docs/guide/pages-routing/loaders.md
+++ b/docs/guide/pages-routing/loaders.md
@@ -95,6 +95,24 @@ export default function UsersPage(props: Props) {
}
```
+```tsx [Hono]
+// pages/users/index.tsx
+import type { Props } from './index.server';
+
+export default function UsersPage(props: Props) {
+ return (
+ <>
+
Users
+
+ {props.users.map((u) => (
+
{u.name}
+ ))}
+
+ >
+ );
+}
+```
+
:::
## Deferred Props
@@ -161,7 +179,7 @@ In production, an unexpected error in a deferred prop reaches the page as
`Internal Server Error`; throw an
[`HTTPException`](../../integrations/hono.md#utilities) to show your own message.
-In Vue, Svelte, and Solid, `Deferred` behaves as a [discriminated union](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#discriminated-unions) with three states:
+In Vue, Svelte, Solid, and Hono, `Deferred` behaves as a [discriminated union](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#discriminated-unions) with three states:
```ts
type Deferred =
@@ -227,6 +245,25 @@ export default function Dashboard(props: Props) {
}
```
+```tsx [Hono]
+import type { Props } from './dashboard.server';
+
+export default function Dashboard(props: Props) {
+ return (
+
+
Projects ({props.projects.length})
+ {props.usage.loading ? (
+
Loading usage...
+ ) : props.usage.error ? (
+
Failed: {props.usage.error.message}
+ ) : (
+
{props.usage.value.requests} requests
+ )}
+
+ );
+}
+```
+
:::
### Deferred Props After Mutations
diff --git a/docs/guide/pages-routing/markdown.md b/docs/guide/pages-routing/markdown.md
index ed4b4c04f..eff419c33 100644
--- a/docs/guide/pages-routing/markdown.md
+++ b/docs/guide/pages-routing/markdown.md
@@ -57,6 +57,10 @@ npm install @void/md @void/svelte
npm install @void/md @void/solid
```
+```sh [Hono]
+npm install @void/md @void/hono hono
+```
+
:::
Add the plugin to your Vite config **after** the framework adapter:
@@ -111,6 +115,18 @@ export default defineConfig({
});
```
+```ts [Hono]
+import { voidHono } from '@void/hono/plugin';
+// vite.config.ts
+import { voidMarkdown } from '@void/md/plugin';
+import { defineConfig } from 'vite';
+import { voidPlugin } from 'void';
+
+export default defineConfig({
+ plugins: [voidPlugin(), voidHono(), voidMarkdown()],
+});
+```
+
:::
## Page Anatomy
@@ -228,6 +244,20 @@ export default function DocsLayout(props) {
}
```
+```tsx [Hono]
+import { useFrontmatter } from '@void/md';
+
+export default function DocsLayout(props) {
+ const fm = useFrontmatter();
+ return (
+
+
{fm.title}
+ {props.children}
+
+ );
+}
+```
+
:::
Island components can also call `useFrontmatter()`. Keep frontmatter on pages with islands safe to share with the browser.
diff --git a/docs/guide/pages-routing/overview.md b/docs/guide/pages-routing/overview.md
index 2500b4da2..d20f0a945 100644
--- a/docs/guide/pages-routing/overview.md
+++ b/docs/guide/pages-routing/overview.md
@@ -4,7 +4,7 @@ outline: deep
# Pages Routing
-Put UI components in `pages/` to make them routes. A page's server loader returns data, and the component receives it as props. This pattern is inspired by [Inertia.js](https://inertiajs.com/) and works with React, Vue, Svelte, and Solid.
+Put UI components in `pages/` to make them routes. A page's server loader returns data, and the component receives it as props. This pattern is inspired by [Inertia.js](https://inertiajs.com/) and works with React, Vue, Svelte, Solid, and Hono.
Pages mode starts when a `pages/` directory exists. It can live alongside `routes/`: use pages for UI and routes for APIs. Page components normally run on the server for the first render and in the browser for navigation and interaction.
@@ -12,7 +12,7 @@ You can also use your own client-side router and call Void's APIs with [typed fe
## Setup
-In an empty project, `void init` can set up Pages for you. Choose Vite+ or plain Vite, then React, Vue, Svelte, or Solid and a database or static starter. The generated app includes the matching Vite config and page files.
+In an empty project, `void init` can set up Pages for you. Choose Vite+ or plain Vite, then React, Vue, Svelte, Solid, or Hono and a database or static starter. The generated app includes the matching Vite config and page files.
If you're adding Pages mode manually, install a framework adapter alongside `void`:
@@ -34,6 +34,10 @@ npm install @void/svelte
npm install @void/solid
```
+```sh [Hono]
+npm install @void/hono hono
+```
+
:::
Add both plugins to your Vite config:
@@ -84,9 +88,20 @@ export default defineConfig({
});
```
+```ts [Hono]
+// vite.config.ts
+import { voidHono } from '@void/hono/plugin';
+import { defineConfig } from 'vite';
+import { voidPlugin } from 'void';
+
+export default defineConfig({
+ plugins: [voidPlugin(), voidHono()],
+});
+```
+
:::
-Each adapter includes its framework's Vite plugin. Pass framework plugin options via `voidReact({ react: { ... } })`, `voidVue({ vue: { ... } })`, `voidSvelte({ svelte: { ... } })`, or `voidSolid({ solid: { ... } })` if needed.
+Each adapter includes its framework's Vite plugin. Pass framework plugin options via `voidReact({ react: { ... } })`, `voidVue({ vue: { ... } })`, `voidSvelte({ svelte: { ... } })`, or `voidSolid({ solid: { ... } })` if needed. The Hono adapter compiles JSX with `hono/jsx` and needs no other plugin; for type checking, set `"jsx": "react-jsx"` and `"jsxImportSource": "hono/jsx"` in `tsconfig.json`.
## Directory Structure
@@ -197,6 +212,14 @@ import { routeUrl } from 'void/routes';
View
```
+```tsx [Hono]
+import { Link } from "@void/hono";
+import { routeUrl } from 'void/routes';
+
+Users
+View
+```
+
:::
With [`routing.typedRoutes`](../type-safety.md#checked-url-strings), which apps created with `void init` have on, `href` and the router methods below reject plain strings such as `"/user"` that don't match a route.
@@ -233,7 +256,7 @@ With [`routing.typedRoutes`](../type-safety.md#checked-url-strings), which apps
For programmatic navigation, use `useRouter()`. Pass a typed destination object to `visit()`, `prefetch()`, or `flush()`:
```ts
-import { useRouter } from '@void/vue'; // or "@void/react", "@void/svelte", "@void/solid"
+import { useRouter } from '@void/vue'; // or "@void/react", "@void/svelte", "@void/solid", "@void/hono"
import type { RouteDestination } from 'void/routes';
const router = useRouter();
@@ -314,6 +337,15 @@ A link is active only on its own path by default. Set `activeMatch="prefix"` to
```
+```tsx [Hono]
+
+```
+
:::
| Current URL | `href="/users"` | `href="/users" activeMatch="prefix"` |
@@ -418,4 +450,10 @@ router.visit('/users', { preserveScroll: true });
```
+```tsx [Hono]
+
+ Users
+
+```
+
:::
diff --git a/docs/guide/pages-routing/view-transitions.md b/docs/guide/pages-routing/view-transitions.md
index 9ea8d038c..b359a1a2a 100644
--- a/docs/guide/pages-routing/view-transitions.md
+++ b/docs/guide/pages-routing/view-transitions.md
@@ -40,6 +40,13 @@ export default defineConfig({
});
```
+```ts [Hono]
+// vite.config.ts
+export default defineConfig({
+ plugins: [voidPlugin(), voidHono({ viewTransitions: true })],
+});
+```
+
:::
This enables view transitions for all navigations, including `Link` clicks, programmatic `router.visit()` calls, and browser back or forward.
@@ -98,6 +105,22 @@ Override the global setting on individual links:
;
```
+```tsx [Hono]
+{
+ /* Disable transition for this link */
+}
+
+ Settings
+;
+
+{
+ /* Enable for just this link (even if globally disabled) */
+}
+
+ About
+;
+```
+
:::
Or programmatically:
diff --git a/docs/index.md b/docs/index.md
index fb76e0505..ea6d4a5c8 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -44,7 +44,7 @@ features:
title: Use Your Favorite Framework
details: Build with Void's adapters or keep your existing Vite framework.
highlights:
- - Ships with adapters for Async React, Vue, Svelte, and Solid
+ - Ships with adapters for Async React, Vue, Svelte, Solid, and Hono
- Supports TanStack Start, SvelteKit, Nuxt, and more
- Build APIs, SPAs, or server-rendered pages
guide:
diff --git a/docs/reference/api.md b/docs/reference/api.md
index 88ebedc7d..e2551684f 100644
--- a/docs/reference/api.md
+++ b/docs/reference/api.md
@@ -28,7 +28,7 @@ Use this reference to find public imports, signatures, and return types. For set
| [Deployment artifacts](./api/deploy.md) | Package built apps for managed deployment. |
| [Types](./api/types.md) | Typed URLs, route types, handler context, and head metadata. |
| [Environment variables](./api/env.md) | Validated environment values and binding types. |
-| [Pages adapters](./api/pages.md) | React, Vue, Svelte, Solid, and Markdown. |
+| [Pages adapters](./api/pages.md) | React, Vue, Svelte, Solid, Hono, and Markdown. |
## User-Facing Imports {#user-facing-imports}
diff --git a/docs/reference/api/pages.md b/docs/reference/api/pages.md
index 2d8eb00bb..8354d350b 100644
--- a/docs/reference/api/pages.md
+++ b/docs/reference/api/pages.md
@@ -8,7 +8,7 @@ Framework adaptors for [Pages Routing](../../guide/pages-routing/overview). Each
## Navigation destinations {#navigation-destinations}
-All four adapters support typed URLs through [`routeUrl()`](./types.md#routeurl-path-options). Pass the returned string to `Link`'s `href`, which has the type [`Href`](./types.md#route-types).
+All five adapters support typed URLs through [`routeUrl()`](./types.md#routeurl-path-options). Pass the returned string to `Link`'s `href`, which has the type [`Href`](./types.md#route-types).
The router's `visit(destination, options?)`, `prefetch(destination, options?)`, and `flush(destination, method?)` accept [`RouteUrlInput`](./types.md#route-types): a string, `URL`, or typed destination object.
@@ -159,9 +159,9 @@ React deferred props returned from `defer()` are Suspense resources. Read them
with React's `use()` inside a `` boundary. React Pages requires React
19 and uses streaming SSR for the initial deferred shell. Rejections throw from
`use()`, so use a normal React error boundary for custom deferred error UI. Vue,
-Svelte, and Solid keep the `{ loading, value, error }` deferred state object.
+Svelte, Solid, and Hono keep the `{ loading, value, error }` deferred state object.
When explicitly annotating props, import `Deferred` from the framework adapter
-package (`@void/react`, `@void/vue`, `@void/svelte`, or `@void/solid`) so the
+package (`@void/react`, `@void/vue`, `@void/svelte`, `@void/solid`, or `@void/hono`) so the
type matches that adapter's client runtime shape.
### React navigation completion {#react-navigation-completion}
@@ -289,6 +289,73 @@ Solid `Link` GET `data` is merged into the rendered `href` query string. Primiti
Solid re-creates the page on GET navigation and whenever the route or its params change, so `useForm()` picks up the destination record's URL and defaults; layouts persist. Within the same record, back/forward, mutations, and `router.refresh()` keep the page and update its props in place, as do resolved deferred props, so read props inside JSX or memos instead of copying them in the component body. Set `preserveState` explicitly to override the default for navigation within the same record.
+## `@void/hono` {#void-hono}
+
+### `voidHono(options?)` {#voidhono-options}
+
+Imported from `"@void/hono/plugin"`. Returns an array of Vite plugins that handle SSR and hydration entry generation for Hono JSX. It compiles JSX with `hono/jsx`, so no other framework plugin is needed. Requires Hono 4.13 or later.
+
+```ts
+import { voidHono } from '@void/hono/plugin';
+
+export default defineConfig({
+ plugins: [voidPlugin(), voidHono()],
+});
+```
+
+For type checking, set the JSX import source in `tsconfig.json`:
+
+```json
+{
+ "compilerOptions": {
+ "jsx": "react-jsx",
+ "jsxImportSource": "hono/jsx"
+ }
+}
+```
+
+**Signature:**
+
+```ts
+function voidHono(options?: VoidHonoOptions): Plugin[];
+```
+
+**Options:**
+
+```ts
+interface VoidHonoOptions {
+ viewTransitions?: boolean; // enable View Transitions API
+ prefetch?: {
+ defaultStrategy?: boolean | LinkPrefetchStrategy | LinkPrefetchStrategy[]; // default: false
+ hoverDelay?: number; // default: 75 (ms)
+ cacheFor?: number | string | [string, string]; // default: '30s'
+ };
+}
+```
+
+### Hono Runtime {#hono-runtime}
+
+Imported from `"@void/hono"`. Import hooks such as `useState` from `"hono/jsx"`.
+
+| Export | Description |
+| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `Link` | Hono JSX component for SPA navigation. Renders `` for GET, `