Full-stack HonoX starter with type-safe CSS-in-JS (PandaCSS), and a Git-backed CMS (Sveltia CMS).
Live demo: https://honox.chen.so, https://honox-ts.vercel.app
| Feature | Details |
|---|---|
| Framework | HonoX — meta-framework on Hono |
| Styling | PandaCSS — type-safe, zero-runtime CSS-in-JS |
| CMS | Sveltia CMS — Git-backed, runs at /admin/ |
| Blog | Markdown posts in content/posts/, rendered at /blog |
| API | Read-only JSON REST API for posts at /api/posts/* |
| SSG | Static site generation via @hono/vite-ssg |
| Deploy | Cloudflare Pages (wrangler.jsonc) |
| Route | File | Purpose |
|---|---|---|
/ |
app/routes/index.tsx |
Homepage — Page Builder-driven (content/pages/index.json), locale-aware |
/blog |
app/routes/blog.tsx |
Post list with tag filtering |
/blog/by-tag/:tag |
app/routes/blog/by-tag/[tag].tsx |
Tag-filtered post list (static) |
/blog/by-author/:author |
app/routes/blog/by-author/[author].tsx |
Author-filtered post list (static) |
/blog/:slug |
app/routes/blog/[slug].tsx |
Individual post |
/admin/ |
public/admin/index.html |
Sveltia CMS UI |
/pages/:slug (+ /pages/:locale/:slug) |
app/routes/pages/[slug].tsx |
Dynamic CMS-built pages |
/api/posts/index.json |
app/routes/api/posts/index.json.ts |
Post collection (JSON) |
/api/posts/:slug.json |
app/routes/api/posts/[slug].json.ts |
Single post detail (JSON) |
/api/posts/search.json |
app/routes/api/posts/search.json.ts |
Search index (JSON) |
/api/posts/by-author/:author.json |
app/routes/api/posts/by-author/[author].json.ts |
Posts by author (JSON) |
See docs/ARCHITECTURE.md for UI components architecture details.
- Write — Markdown files in
content/posts/*.mdwith YAML frontmatter. - Manage — Visit
/admin/to edit posts. - Build —
bun run buildgenerates static HTML for post list and individual posts.
- Design — Create pages in
content/pages/*.jsonusing the CMS UI. This includes the homepage itself (content/pages/index.json). - Components — Choose from 25+ UI components (Stack, Card, Dialog, etc.).
- Nesting — Build complex layouts with recursive nesting (e.g., a Card inside a Stack inside another Stack).
- Render — The
PageRenderercomponent (app/components/page-renderer.tsx) maps JSON data to themed UI components, loaded viaapp/lib/pages.ts. - Translate — Add
content/pages/<locale>/<slug>.jsonfor a translated page;loadPage()falls back to the default-locale file for anything not translated.
A read-only JSON REST API over the same content/posts/*.md files that back /blog, prerendered by SSG like every other route. Because the site deploys as static files with no live server at request time, every endpoint's URL includes a literal .json suffix — that's the exact filename the build writes to dist/, so the same path works identically in dev (bun run dev) and once deployed.
| Endpoint | Description |
|---|---|
GET /api/posts/index.json |
All published posts (drafts excluded in production), newest first. Shape: { generated, total, tags, posts: BlogPost[] }. |
GET /api/posts/:slug.json |
One post's full detail: frontmatter fields + rendered html + up to 3 relatedPosts sharing a tag. 404 with { "error": "Not found" } for a missing or (in production) draft slug. |
GET /api/posts/search.json |
The search index the Search island fetches client-side. Shape: { generated, entries: SearchIndexEntry[] }. |
GET /api/posts/by-author/:author.json |
All posts by a given author, newest first. Shape: { generated, author, total, posts: BlogPost[] }. Returns empty array if no posts match. |
Implementation: app/lib/posts.ts (loadPosts, loadPostBySlug, loadPostsByAuthor) backs all routes. app/routes/api/posts/_404.tsx scopes a JSON not-found handler to this namespace so API errors don't fall back to the site's HTML 404 page.
This starter contains an advanced layout builder inside the Sveltia CMS pages collection. Users can construct complex, responsive, dynamic pages directly from the CMS UI.
We support a full collection of over 25+ rich presentational and interactive components:
- Layout & Structure:
Stack(Direction/Align/Justify/Gap),Group(Grow/Attached),Fieldset(Legend/Helper/Error) - Text & Typography:
Heading(Level/Size),Text(Content/Size) - UI Elements:
Button(Variant/Palette/Size),Badge(Variant/Palette/Size),Alert(Status/Variant),Card(Variant/Size/Clickable) - Form & Controls:
Checkbox,Combobox(Items list/Clear trigger),Field,RadioGroup,SegmentGroup,Slider,Switch - Feedback & Loaders:
Progress(Linear/Circular),Skeleton(NoOfLines/Circle),Spinner,Toast(global toast host, paired with a Button's raw onClick) - Overlays & Dialogs:
Collapsible(Trigger/Open),Popover(ShowArrow/Closable),Dialog(Cancel/Confirm/Closable),Drawer(Cancel/Confirm/Closable),Dropdown(Nestable item action list) - Tables & Data:
PaginatedTable,Pagination
Components like Stack, Fieldset, Group, HoverCard, Popover, Collapsible, Dialog, and Drawer fully support recursive children nesting. Through carefully designed YAML anchors and references in Sveltia CMS public/admin/config.yml and a smart layout compiler inside app/components/page-renderer.tsx, users can nest components (e.g. Buttons/Skeletons inside a Card inside a Collapsible inside a Stack) to build sophisticated dashboard layouts.
Sveltia CMS is configured in public/admin/config.yml. You can use it locally or with a Git backend:
- GitHub:
name: github - GitLab:
name: gitlab - Bitbucket:
name: bitbucket - Azure:
name: azure
See Sveltia CMS docs for details.
- Bun 1.0+
- Node.js 18+ (for PandaCSS)
| Command | Purpose |
|---|---|
bun run dev |
Dev server with HMR (http://localhost:5173) |
bun run build |
Client + server build + SSG |
bun run start --static |
Serve dist/ statically (no SSR) |
bun run deploy |
Deploy to Cloudflare Pages |
app/
components/page-renderer.tsx # Dynamic Page layout compiler
components/ui/ # Public component API
islands/ # Client-side interactive islands
routes/ # File-based routing
blog.tsx # Post list
blog/[slug].tsx # Individual post
blog/by-tag/[tag].tsx # Tag-filtered post list
blog/by-author/[author].tsx # Author-filtered post list
pages/[slug].tsx # Page builder SSG route
api/posts/ # Read-only posts REST API
index.json.ts # GET /api/posts/index.json — collection
[slug].json.ts # GET /api/posts/:slug.json — single post
search.json.ts # GET /api/posts/search.json — search index
by-author/[author].json.ts # GET /api/posts/by-author/:author.json
_404.tsx # JSON 404s scoped to /api/posts/*
lib/posts.ts # Post loading/parsing shared by blog pages + API
lib/pages.ts # Page builder JSON loading, locale-aware (used by / and /pages/:slug)
utils/
markdown.ts # Frontmatter parser + MD→HTML
content/posts/ # Blog post markdown files
content/pages/ # Page builder JSON layouts (index.json is the homepage)
content/pages/<locale>/ # Translated page layouts, e.g. content/pages/zh/index.json
public/admin/ # Sveltia CMS static files
config.yml # CMS configuration
index.html # CMS UI