Getting Started
Introduction
Yawn is a TypeScript-first, HTML-based web framework. Write .yawn files, run one command, ship a real site. No bundler config, no JSX, no boilerplate.
Yawn is in active development. The API is stable for v1.0 but some packages are still maturing.
What makes Yawn different
Most frameworks ask you to learn a new paradigm before writing a single line. Yawn doesn't. If you know HTML, you already know 80% of it.
HTML-first
Write real HTML. No JSX, no virtual DOM ceremony, no mental model switch.
Zero config
Tailwind CDN is injected automatically. No webpack, no vite config, no postcss setup.
Instant reactivity
Declare a variable, use it in a template. Yawn wires the rest.
SSR out of the box
Every page server-renders to HTML first. Fast initial load, great SEO.
File-based routing
The file system is your router. Drop a file in src/pages/, get a route.
TypeScript native
Full TypeScript support throughout. No extra setup.
How it works
You write a .yawn file. The compiler reads <template>, <script>, and <style>, generates a server-rendered HTML page with a hydration script, and serves it. The browser renders HTML immediately, then Yawn's tiny runtime attaches reactivity.
hello.yawn
class="text-white/class="text-orange-400">30"><class="text-indigo-class="text-orange-400">400">templateclass="text-white/class="text-orange-400">30">>
class="text-white/class="text-orange-400">30"><class="text-blue-class="text-orange-400">400">div class="min-h-screen bg-[#0a0a0f] text-white flex items-center justify-center px-class="text-orange-400">4">
class="text-white/class="text-orange-400">30"><class="text-blue-class="text-orange-400">400">div class="text-center max-w-lg">
class="text-white/class="text-orange-400">30"><class="text-blue-class="text-orange-400">400">div class="inline-flex items-center gap-class="text-orange-400">2 bg-white/class="text-orange-400">5 border border-white/class="text-orange-400">10 rounded-full px-class="text-orange-400">4 py-class="text-orange-400">1.class="text-orange-400">5 text-xs text-white/class="text-orange-400">50 mb-class="text-orange-400">8">
class="text-white/class="text-orange-400">30"><class="text-blue-class="text-orange-400">400">span class="w-class="text-orange-400">1.class="text-orange-400">5 h-class="text-orange-400">1.class="text-orange-400">5 bg-green-class="text-orange-400">400 rounded-full">class="text-white/class="text-orange-400">30"><class="text-blue-class="text-orange-400">400">/spanclass="text-white/class="text-orange-400">30">>
Live on Yawn v1.class="text-orange-400">0
class="text-white/class="text-orange-400">30"><class="text-blue-class="text-orange-400">400">/divclass="text-white/class="text-orange-400">30">>
class="text-white/class="text-orange-400">30"><class="text-blue-class="text-orange-400">400">h1 class="text-5xl font-black tracking-tight mb-class="text-orange-400">4">Hello, class="text-yellow-300">{{ name }}class="text-white/class="text-orange-400">30"><class="text-blue-class="text-orange-400">400">/h1class="text-white/class="text-orange-400">30">>
class="text-white/class="text-orange-400">30"><class="text-blue-class="text-orange-400">400">p class="text-white/class="text-orange-400">40 mb-class="text-orange-400">8">You have clicked class="text-yellow-300">{{ count }} class="text-yellow-300">{{ count === class="text-orange-400">1 ? class="text-green-class="text-orange-400">400">'time' : class="text-green-class="text-orange-400">400">'times' }}class="text-white/class="text-orange-400">30"><class="text-blue-class="text-orange-400">400">/pclass="text-white/class="text-orange-400">30">>
class="text-white/class="text-orange-400">30"><class="text-blue-class="text-orange-400">400">div class="flex items-center gap-class="text-orange-400">3 justify-center">
class="text-white/class="text-orange-400">30"><class="text-blue-class="text-orange-400">400">button class="text-green-400">@click="count++" class="bg-white text-black px-class="text-orange-400">6 py-class="text-orange-400">2.class="text-orange-400">5 rounded-lg font-semibold hover:bg-white/class="text-orange-400">90 transition-colors">
Click me
class="text-white/class="text-orange-400">30"><class="text-blue-class="text-orange-400">400">/buttonclass="text-white/class="text-orange-400">30">>
class="text-white/class="text-orange-400">30"><class="text-blue-class="text-orange-400">400">button class="text-green-400">@click="count = class="text-orange-400">0" class="border border-white/class="text-orange-400">10 text-white/class="text-orange-400">50 px-class="text-orange-400">6 py-class="text-orange-400">2.class="text-orange-400">5 rounded-lg hover:text-white hover:border-white/class="text-orange-400">30 transition-colors">
Reset
class="text-white/class="text-orange-400">30"><class="text-blue-class="text-orange-400">400">/buttonclass="text-white/class="text-orange-400">30">>
class="text-white/class="text-orange-400">30"><class="text-blue-class="text-orange-400">400">/divclass="text-white/class="text-orange-400">30">>
class="text-white/class="text-orange-400">30"><class="text-blue-class="text-orange-400">400">/divclass="text-white/class="text-orange-400">30">>
class="text-white/class="text-orange-400">30"><class="text-blue-class="text-orange-400">400">/divclass="text-white/class="text-orange-400">30">>
class="text-white/class="text-orange-400">30"><class="text-indigo-class="text-orange-400">400">/templateclass="text-white/class="text-orange-400">30">>
class="text-white/class="text-orange-400">30"><class="text-indigo-class="text-orange-400">400">scriptclass="text-white/class="text-orange-400">30">>
class="text-purple-class="text-orange-400">400">let name = "World";
class="text-purple-class="text-orange-400">400">let count = class="text-orange-400">0;
class="text-white/class="text-orange-400">30"><class="text-indigo-class="text-orange-400">400">/scriptclass="text-white/class="text-orange-400">30">>Key principles
- HTML-first
- Developers write HTML, not JSX. The template is real HTML with reactive attributes.
- Zero config
- Tailwind CSS is auto-included via CDN. No bundler, no postcss, no config file.
- Minimal script
- The script block only holds variable declarations. Event handlers live inline in the template.
- SSR + hydration
- Pages are server-rendered to full HTML, then hydrated by a tiny runtime.
- File-based routing
- src/pages/about.yawn becomes /about automatically. No router config needed.
Quick start
terminal
npx create-yawn@latest my-site