Public showcase website for FormKit themes. Nuxt 3 app with live theme editing and CLI integration.
themes.formkit.com/
├── app.vue # Root layout
├── nuxt.config.ts # Nuxt + Tailwind v4 CDN config
├── formkit.config.ts # FormKit with Pro inputs
├── pages/
│ ├── index.vue # Theme showcase + selector
│ └── editor.vue # Full theme editor
├── components/
│ ├── AppHeader.vue # Navigation + dark mode
│ ├── DownloadModal.vue # TW3/TW4 CLI commands
│ └── FormKitExampleScroller.vue
├── server/api/
│ ├── themes.ts # GET /api/themes
│ └── generate.post.ts # POST /api/generate
├── src/
│ └── manifest.ts # Theme imports
├── utils/
│ └── parseVariables.ts # URL param parsing
└── plugins/
├── global-components.js
└── analytics.client.js
Configured in nuxt.config.ts:
script: [
{ src: 'https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4' }
],
style: [
{
type: 'text/tailwindcss',
innerHTML: '@custom-variant dark (&:where(.dark, .dark *));'
}
]// src/manifest.ts
export const themeManifest = {
regenesis: () => import('@formkit/theme-regenesis'),
starter: () => import('@formkit/theme-starter'),
'regenesis-tw3': () => import('@formkit/theme-regenesis-tw3'),
'starter-tw3': () => import('@formkit/theme-starter-tw3'),
}// pages/index.vue
watch(activeTheme, async (themeName) => {
const { default: theme } = await themeManifest[themeName]()
config.rootClasses = rootClasses(theme(parseVariables()).tailwind())
document.dispatchEvent(new Event('FormKitTheme'))
})Returns array of available theme metadata.
Generates theme code file.
// Request body (validated with Valibot)
{
theme: string, // Required
variables?: string, // "var1=val1,var2=val2"
ts?: 'true'|'false', // TypeScript output
semantic?: 'true'|'false'
}FORMKIT_PRO_KEY=fk-*** # Pro inputs license
KV_DRIVER=cloudflare-kv-http # Analytics storage
KV_ACCOUNT_ID=***
KV_NAMESPACE_ID=***
KV_API_TOKEN=***
NPM_TOKEN=*** # Private package accesspnpm dev # Nuxt dev server (port 3000)
pnpm build # Production build
pnpm generate # Static generation
pnpm preview # Preview production build// formkit.config.ts
{
plugins: [proPlugin, createMultiStepPlugin()],
inputs: { barcode },
icons: { ...genesisIcons, github, external, sun, moon },
config: {
rootClasses: rootClasses(theme().tailwind()),
},
}- Theme selector cards
- Live form examples (FormKitExampleScroller)
- Download modal for CLI commands
- "Customize" link to editor
- Full theme editor integration
- URL-based state:
?theme=name&variables=... - FormKitKitchenSink for all inputs
- Real-time variable updates
// editor.vue
import { createEditor } from '@formkit/theme-editor'
onMounted(() => {
createEditor()
window.__FORMKIT_AVAILABLE_THEMES__ = themeManifest
})
// Listen for variable changes
document.addEventListener('formkit-theme-update', (e) => {
// Update URL with new variables
router.replace({ query: { theme, variables: e.detail.variables }})
})themes.formkit.com (this package)
↓ imports and displays
├── @formkit/theme-regenesis (main theme)
├── @formkit/theme-starter (starter theme)
├── @formkit/theme-regenesis-tw3 (TW3 variant)
├── @formkit/theme-starter-tw3 (TW3 variant)
├── @formkit/theme-editor (editor UI)
├── @formkit/theme-creator (rootClasses)
└── @formkit/pro (premium inputs demo)
- Add dependency in
package.json - Add to
src/manifest.ts - Theme appears in selector automatically
Edit components/DownloadModal.vue:
- TW3/TW4 variant handling
- CLI command format
- Copy functionality
Edit formkit.config.ts:
- Add/remove plugins
- Modify icons
- Change default theme
Uses Vue Fathom (privacy-first):
- Site ID:
LFEMPNAQ - Configured in
plugins/analytics.client.js
Static generation + Nitro server for API routes:
pnpm generatefor static files- API routes need Node.js runtime
- Cloudflare KV for analytics storage