on master help sign in
Expand demo.hl to comprehensively showcase htmlang language features

Demonstrates @theme, @let (computed), @define, @mixin, @keyframes, @raw, @fn with defaults, @if/@else/@assert, @each/@else/@repeat/@for/@match, conditional values, pseudo-states, all major elements (@header, @section, @article, @form, @table, @details, @time, @meter, etc.), inline elements, grid, animations, color filters, and more.

commit377f11d32cb8c10fd2b6a0ea9c09e704c2b25cff authoriko <mail@iko.soy> dateThu 16 Apr 2026, 11:37 (6 months ago) parentb9bafda
3 files changed+328−143
examples/demo.hl+324−35 examples/demo.html+3−107 examples/demo.html.map+1−1
examples/demo.hl+324−35
@@ -1,41 +1,330 @@
1+-- A comprehensive tour of htmlang: layout, style, components, and control flow.
12@page htmlang Demo
2−@let primary #3b82f6
3−@let gap 20
3+@lang en
4+@meta description A one-page tour of htmlang.
5+@og title htmlang
6+@og type website
47
5−-- reusable card with hover effect
6−@fn card $title
7− @el [padding 20, background white, rounded 8, border 1 #e5e7eb, hover:border 1 $primary, transition all 0.15s ease, cursor pointer]
8− @text [bold] $title
8+-- Design tokens become both $vars and CSS custom properties
9+@theme
10+ primary #3b82f6
11+ ink #0f172a
12+ muted #64748b
13+ subtle #f8fafc
14+
15+-- Computed @let with arithmetic
16+@let base 8
17+@let gap = $base * 2
18+@let gutter = $gap + $base
19+
20+-- Reusable attribute bundle
21+@define card [
22+ padding $gap,
23+ background white,
24+ rounded $base,
25+ border 1 #e5e7eb,
26+ shadow 0 1px 3px rgba(0,0,0,0.05)
27+]
28+
29+-- Composable style group (used with spread)
30+@mixin interactive [
31+ cursor pointer,
32+ hover:shadow 0 4px 12px rgba(0,0,0,0.08),
33+ transition all 0.2s ease
34+]
35+
36+-- Keyframes using attribute syntax
37+@keyframes fade-up
38+ from [opacity 0, transform translateY(8px)]
39+ to [opacity 1, transform translateY(0)]
40+
41+-- Raw HTML escape hatch
42+@raw """
43+<noscript><style>.needs-js{display:none}</style></noscript>
44+"""
45+
46+-- Component with default parameter + @children slot
47+@fn card $title $icon=◆
48+ @article [$card, ...$interactive, animate fade-up 0.3s ease]
49+ @row [spacing 10, align-items center]
50+ @text [size 20, color $primary] $icon
51+ @text [bold, size 16, color $ink] $title
952 @children
1053
11−-- page layout function
12−@fn page-section $title
13− @column [spacing 10]
14− @text [bold, size 24, color #333] $title
54+-- Component that wraps children in a titled section (function + slot)
55+@fn titled $title
56+ @section [spacing 12, padding-y $base]
57+ @text [bold, size 22, color $ink] $title
1558 @children
1659
17−@column [max-width 800, center-x, padding 40, spacing $gap]
18− @row [spacing $gap]
19− @column [width fill, spacing 10]
20− @text [bold, size 32] Welcome to htmlang
21− @paragraph
22− A minimalist layout language that compiles to
23− {@text [bold, color $primary] static HTML}.
24− @image [width 80, height 80, rounded 40, alt "A stock photo"] https://picsum.photos/80
25−
26− -- cards using @fn with hover
27− @page-section [title Features]
28− @row [wrap, spacing 10]
29− @card [title Simple]
30− Write layouts without CSS
31− @card [title Fast]
32− Compiles to a single HTML file
33− @card [title Minimal]
34− No JavaScript required
35−
36− -- footer with hover button
37− @row [spacing 10]
38− @el [padding 16, background $primary, hover:background #2563eb, active:background #1d4ed8, rounded 8, transition all 0.15s ease, cursor pointer] > @link https://github.com
39− @text [color white, bold] Get Started
40− @el [width fill]
41− @text [color #888] © 2026
60+-- Top-level layout
61+@column [
62+ max-width 960,
63+ center-x,
64+ padding 32,
65+ spacing $gutter,
66+ background white,
67+ dark:background #0b1220,
68+ dark:color #e2e8f0
69+]
70+
71+ -- Header: nav + hero
72+ @header [spacing $base]
73+ @nav [spacing 6, color $muted, size 13]
74+ @row [spacing 6, align-items center]
75+ @link [color $muted] / Home
76+ @text /
77+ @link [color $muted] /demos Demos
78+ @text /
79+ @text [color $ink] htmlang
80+
81+ @row [spacing $gap, align-items center]
82+ @column [width fill, spacing 6]
83+ @text [bold, size 40, color $ink, dark:color white] Welcome to htmlang
84+ @paragraph [line-height 1.6, color $muted]
85+ A minimalist layout language that compiles to
86+ {@text [bold, color $primary] static HTML} — no JS, no build step.
87+ Visit the {@link [color $primary, underline] https://github.com repo} for more.
88+ @image [width 72, height 72, rounded 36, alt "Avatar"] https://picsum.photos/72
89+
90+ @hr [border-top 1 #e5e7eb]
91+
92+ -- Feature grid using @card + @titled components
93+ @titled [title Features]
94+ @row [wrap, gap $base]
95+ @card [title Simple, icon ✦]
96+ Write layouts without CSS classes.
97+ @card [title Fast, icon ⚡]
98+ Compiles to a single self-contained HTML file.
99+ @card [title Minimal, icon ○]
100+ Zero runtime JavaScript by default.
101+ @card [title Typed]
102+ LSP with diagnostics and go-to-definition.
103+
104+ -- Typography showcase: inline elements, blockquote, code
105+ @titled [title Typography]
106+ @paragraph [line-height 1.7]
107+ A quick brown fox jumps over {@text [bold] the lazy} {@text [italic] dog}.
108+ Press {@kbd [
109+ padding 2 6, background #f1f5f9, rounded 4,
110+ font monospace, size 13
111+ ] Ctrl+K} to search. {@mark [background #fef08a] Highlighted} uses mark.
112+ {@abbr [title HyperText Markup Language + language] htmlang} is an abbreviation.
113+
114+ @blockquote [
115+ padding-inline-start $gap, border-left 3 $primary,
116+ color $muted, italic
117+ ]
118+ Layout is code. Style is code. Everything should compose.
119+ @cite — Anonymous
120+
121+ @pre [
122+ background #0f172a, color #e2e8f0,
123+ padding 16, rounded 8, font monospace, size 13,
124+ overflow-x auto
125+ ]
126+ @raw """
127+@fn button $label
128+ @el [padding 12, background blue]
129+ @text $label
130+"""
131+
132+ -- Control flow: @each, @else, @repeat, @for, @match, if()
133+ @titled [title Control flow]
134+ @column [spacing 6]
135+ @each $name, $role in Alice Engineer, Bob Designer, Carol PM
136+ @row [spacing 10, align-items baseline]
137+ @text [bold, min-width 80] $name
138+ @text [color $muted] $role
139+
140+ -- @each ... @else fallback for empty list
141+ @let nothing ""
142+ @each $x in $nothing
143+ @text $x
144+ @else
145+ @text [color $muted, italic, data-state $nothing] (Nothing — @each ... @else fallback)
146+
147+ -- @repeat
148+ @row [spacing 6]
149+ @repeat 6
150+ @el [width 18, height 18, rounded 9, background $primary, opacity 0.4]
151+
152+ -- @for range
153+ @row [spacing 4]
154+ @for $i in 1..6
155+ @el [
156+ width 24, height 24, rounded 4,
157+ background $primary, color white,
158+ text-align center, size 12, bold, line-height 24
159+ ]
160+ $i
161+
162+ -- @if / @else if / @else (with @assert to verify at compile time)
163+ @let count 3
164+ @assert $count == 3
165+ @row [spacing 6, align-items center]
166+ @text [bold, min-width 64] Count:
167+ @if $count == 0
168+ @text [color $muted] Empty
169+ @else if $count == 1
170+ @text [color $primary] Exactly one
171+ @else
172+ @text [color $primary, bold] $count items
173+
174+ -- @match
175+ @let status ready
176+ @match $status
177+ @case pending
178+ @text [color #f59e0b] Pending…
179+ @case ready
180+ @text [color #10b981, bold] ✓ Ready
181+ @case error
182+ @text [color #ef4444] Error
183+ @default
184+ @text Unknown
185+
186+ -- Conditional attribute value + before: pseudo-element
187+ @let emphasized true
188+ @el [
189+ padding 12, rounded 6,
190+ background if($emphasized, $primary, #e5e7eb),
191+ color if($emphasized, white, $ink),
192+ before:content "→ ", before:bold
193+ ]
194+ Conditional styling via {@code if(cond, a, b)}.
195+
196+ -- Forms + pseudo-states
197+ @titled [title Forms]
198+ @form [spacing 10, max-width 420] /subscribe
199+ @label [bold, size 13, for email] Email
200+ @input [
201+ id email, type email, name email,
202+ placeholder you@example.com, required,
203+ padding 10, border 1 #e5e7eb, rounded 6,
204+ focus:border 1 $primary,
205+ valid:border 1 #10b981,
206+ invalid:border 1 #ef4444,
207+ transition border 0.15s ease
208+ ]
209+ @label [bold, size 13, for role] Role
210+ @select [id role, name role, padding 10, border 1 #e5e7eb, rounded 6]
211+ @option [value dev] Developer
212+ @option [value designer] Designer
213+ @option [value other] Other
214+ @label [bold, size 13, for msg] Message
215+ @textarea [
216+ id msg, name msg, rows 3,
217+ padding 10, border 1 #e5e7eb, rounded 6
218+ ]
219+ @row [spacing 8]
220+ @button [
221+ type submit,
222+ padding 10 16, background $primary, color white, bold,
223+ rounded 6, border 0,
224+ hover:background $primary|darken:10,
225+ active:background $primary|darken:20,
226+ transition background 0.15s ease,
227+ cursor pointer
228+ ] Subscribe
229+ @button [
230+ type reset,
231+ padding 10 16, background white,
232+ border 1 #e5e7eb, rounded 6, cursor pointer
233+ ] Reset
234+ @progress [value 60, max 100]
235+
236+ -- Lists and tables
237+ @titled [title Data]
238+ @row [gap $gap, wrap]
239+ @column [width fill, spacing $base, min-width 240]
240+ @text [bold] Unordered
241+ @list [spacing 4]
242+ @item Composable with @each
243+ @item Indent to nest children
244+ @item Bold list items work too
245+ @text [bold] Ordered
246+ @list [ordered]
247+ @item First
248+ @item Second
249+ @item Third
250+
251+ @column [width fill, spacing $base, min-width 240]
252+ @text [bold] Table
253+ @table
254+ @thead
255+ @tr
256+ @th [text-align left, padding 8] Item
257+ @th [text-align right, padding 8] Qty
258+ @tbody
259+ @tr
260+ @td [padding 8, border-top 1 #e5e7eb] Widgets
261+ @td [padding 8, border-top 1 #e5e7eb, text-align right] 12
262+ @tr
263+ @td [padding 8, border-top 1 #e5e7eb] Gadgets
264+ @td [padding 8, border-top 1 #e5e7eb, text-align right] 7
265+
266+ @figure [spacing 6]
267+ @image [alt "A random placeholder", rounded 8] https://picsum.photos/640/200
268+ @figcaption [color $muted, size 13, text-align center]
269+ A placeholder image.
270+
271+ -- Disclosure + named grid areas
272+ @titled [title Disclosure + grid areas]
273+ @details [padding 12, border 1 #e5e7eb, rounded 6, background $subtle]
274+ @summary [bold, cursor pointer] What is htmlang?
275+ @paragraph [color $muted, line-height 1.6, padding-block-start 6]
276+ htmlang is a layout-first language that compiles to a single,
277+ self-contained HTML file with embedded CSS.
278+
279+ -- Implicit @el via bare [attrs] line
280+ [
281+ grid,
282+ grid-template-columns 1fr 2fr,
283+ grid-template-areas "h h" "s m" "f f",
284+ gap $base,
285+ padding $base, background $subtle, rounded 8
286+ ]
287+ @el [grid-area h, padding 10, background $primary, color white, rounded 6, text-align center]
288+ Header
289+ @el [grid-area s, padding 10, background white, rounded 6, border 1 #e5e7eb]
290+ Sidebar
291+ @el [grid-area m, padding 10, background white, rounded 6, border 1 #e5e7eb]
292+ Main
293+ @el [grid-area f, padding 10, background $ink, color white, rounded 6, text-align center]
294+ Footer
295+
296+ -- Misc: address, time, meter
297+ @titled [title Misc]
298+ @address [spacing 4, font-style normal]
299+ @text [bold] htmlang HQ
300+ @text 123 Flexbox Avenue
301+ @link [color $primary] mailto:hi@htmlang.dev hi@htmlang.dev
302+ @row [spacing 10, align-items center]
303+ @text [size 13, color $muted] Published
304+ @time [datetime 2026-04-16, size 13] April 16 2026
305+ @row [spacing 10, align-items center]
306+ @text [size 13, color $muted] Confidence
307+ @meter [value 8, min 0, max 10, low 3, high 7] 8/10
308+
309+ -- Footer: hover/active button, visited link, print-hidden
310+ @footer [
311+ padding-block-start $gutter, margin-block-start $gutter,
312+ border-top 1 #e5e7eb, spacing $base,
313+ print:display none
314+ ]
315+ @row [spacing $base, align-items center]
316+ @el [
317+ padding 12 20, background $primary, color white, bold, rounded 8,
318+ hover:background $primary|darken:10,
319+ active:background $primary|darken:20,
320+ transition all 0.15s ease,
321+ cursor pointer
322+ ] > @link https://github.com
323+ Get Started
324+ @link [
325+ color $primary,
326+ visited:color #8b5cf6,
327+ hover:underline
328+ ] https://github.com Browse source
329+ @el [width fill]
330+ @text [color $muted, size 13] © 2026 htmlang
examples/demo.html+3−107
@@ -1,107 +1,3 @@
1−<!DOCTYPE html>
2−<html>
3−<head>
4−<meta charset="utf-8">
5−<meta name="viewport" content="width=device-width, initial-scale=1">
6−<title>htmlang Demo</title>
7−<link rel="preload" href="https://picsum.photos/80" as="image">
8−<link rel="dns-prefetch" href="//picsum.photos">
9−<link rel="dns-prefetch" href="//github.com">
10−<style>
11−*, *::before, *::after { box-sizing: border-box; }
12−body { margin: 0; font-family: system-ui, -apple-system, sans-serif; }
13−img { display: block; }
14−a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
15−@layer htmlang {
16− .a {display:flex;flex-direction:column;max-width:800px;margin-left:auto;margin-right:auto;padding:40px;gap:20px;}
17− .b {display:flex;flex-direction:row;gap:20px;}
18− .c {display:flex;flex-direction:column;flex:1;min-width:0;gap:10px;}
19− .d {font-weight:bold;font-size:32px;}
20− .e {margin:0;}
21− .f {font-weight:bold;color:#3b82f6;}
22− .g {width:80px;height:80px;border-radius:40px;}
23− .h {display:flex;flex-direction:column;gap:10px;}
24− .i {font-weight:bold;font-size:24px;color:#333;}
25− .j {display:flex;flex-direction:row;flex-wrap:wrap;gap:10px;}
26− .k {display:flex;flex-direction:column;padding:20px;background:white;border-radius:8px;border:1px solid #e5e7eb;transition:all 0.15s ease;cursor:pointer;}
27− .k:hover {border:1px solid #3b82f6;}
28− .l {font-weight:bold;}
29− .m {display:flex;flex-direction:row;gap:10px;}
30− .n {display:flex;flex-direction:column;padding:16px;background:#3b82f6;border-radius:8px;transition:all 0.15s ease;cursor:pointer;}
31− .n:hover {background:#2563eb;}
32− .n:active {background:#1d4ed8;}
33− .o {color:white;font-weight:bold;}
34− .p {display:flex;flex-direction:column;flex:1;min-width:0;}
35− .q {color:#888;}
36−}
37−</style>
38−</head>
39−<body>
40−<!-- @column line 17 -->
41−<div class="a" data-hl-line="17" data-hl-el="column">
42− <!-- @row line 18 -->
43− <div class="b" data-hl-line="18" data-hl-el="row">
44− <!-- @column line 19 -->
45− <div class="c" data-hl-line="19" data-hl-el="column">
46− <!-- @text line 20 -->
47− <span class="d" data-hl-line="20" data-hl-el="text">
48−Welcome to htmlang </span>
49− <!-- @paragraph line 21 -->
50− <p class="e" data-hl-line="21" data-hl-el="paragraph">
51−A minimalist layout language that compiles to <span class="f">
52−static HTML </span>. </p>
53− </div>
54− <!-- @image line 24 -->
55− <img src="https://picsum.photos/80" class="g" alt="&quot;A stock photo&quot;" data-hl-line="24" data-hl-el="image" fetchpriority="high">
56− </div>
57− <!-- @column line 13 -->
58− <div class="h" data-hl-line="13" data-hl-el="column">
59− <!-- @text line 14 -->
60− <span class="i" data-hl-line="14" data-hl-el="text">
61−Features </span>
62− <!-- @row line 28 -->
63− <div class="j" data-hl-line="28" data-hl-el="row">
64− <!-- @el line 7 -->
65− <div class="k" data-hl-line="7" data-hl-el="el">
66− <!-- @text line 8 -->
67− <span class="l" data-hl-line="8" data-hl-el="text">
68−Simple </span>
69− <span>Write layouts without CSS</span>
70− </div>
71− <!-- @el line 7 -->
72− <div class="k" data-hl-line="7" data-hl-el="el">
73− <!-- @text line 8 -->
74− <span class="l" data-hl-line="8" data-hl-el="text">
75−Fast </span>
76− <span>Compiles to a single HTML file</span>
77− </div>
78− <!-- @el line 7 -->
79− <div class="k" data-hl-line="7" data-hl-el="el">
80− <!-- @text line 8 -->
81− <span class="l" data-hl-line="8" data-hl-el="text">
82−Minimal </span>
83− <span>No JavaScript required</span>
84− </div>
85− </div>
86− </div>
87− <!-- @row line 37 -->
88− <div class="m" data-hl-line="37" data-hl-el="row">
89− <!-- @el line 38 -->
90− <div class="n" data-hl-line="38" data-hl-el="el">
91− <!-- @link line 38 -->
92− <a href="https://github.com" rel="noopener noreferrer" target="_blank" data-hl-line="38" data-hl-el="link">
93− <!-- @text line 39 -->
94− <span class="o" data-hl-line="39" data-hl-el="text">
95−Get Started </span>
96− </a>
97− </div>
98− <!-- @el line 40 -->
99− <div class="p" data-hl-line="40" data-hl-el="el">
100− </div>
101− <!-- @text line 41 -->
102− <span class="q" data-hl-line="41" data-hl-el="text">
103−© 2026 </span>
104− </div>
105−</div>
106−</body>
107−</html>
1+<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>htmlang Demo</title><meta name="theme-color" content="#3b82f6"><link rel="preload" href="https://picsum.photos/72" as="image"><link rel="preload" href="https://picsum.photos/640/200" as="image"><link rel="dns-prefetch" href="//github.com"><link rel="dns-prefetch" href="//picsum.photos"><meta name="description" content="A one-page tour of htmlang."><meta property="og:title" content="htmlang"><meta property="og:type" content="website"><style>*,*::before,*::after{box-sizing:border-box}body{margin:0;font-family:system-ui,-apple-system,sans-serif}img{display:block}a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible{outline:2px solid currentColor;outline-offset:2px}:root{--primary:#3b82f6;--ink:#0f172a;--muted:#64748b;--subtle:#f8fafc;}@layer htmlang{.a{display:flex;flex-direction:column;max-width:960px;margin-left:auto;margin-right:auto;padding:32px;gap:24px;background:white;}.b{display:flex;flex-direction:column;gap:8px;}.c{display:flex;flex-direction:column;gap:6px;color:#64748b;font-size:13px;}.d{display:flex;flex-direction:row;gap:6px;align-items:center;}.e{color:#64748b;}.f{color:#0f172a;}.g{display:flex;flex-direction:row;gap:16px;align-items:center;}.h{display:flex;flex-direction:column;flex:1;min-width:0;gap:6px;}.i{font-weight:bold;font-size:40px;color:#0f172a;}.j{margin:0;line-height:1.6;color:#64748b;}.k{font-weight:bold;color:#3b82f6;}.l{color:#3b82f6;text-decoration:underline;}.m{width:72px;height:72px;border-radius:36px;}.n{border-top:1px solid #e5e7eb;}.o{display:flex;flex-direction:column;gap:12px;padding-top:8px;padding-bottom:8px;}.p{font-weight:bold;font-size:22px;color:#0f172a;}.q{display:flex;flex-direction:row;flex-wrap:wrap;gap:8px;}.r{display:flex;flex-direction:column;padding:16px;background:white;border-radius:8px;border:1px solid #e5e7eb;box-shadow:0 1px 3px rgba(0,0,0,0.05);cursor:pointer;transition:all 0.2s ease;animation:fade-up 0.3s ease;}.r:hover{box-shadow:0 4px 12px rgba(0,0,0,0.08);}.s{display:flex;flex-direction:row;gap:10px;align-items:center;}.t{font-size:20px;color:#3b82f6;}.u{font-weight:bold;font-size:16px;color:#0f172a;}.v{margin:0;line-height:1.7;}.w{font-weight:bold;}.x{font-style:italic;}.y{font-family:ui-monospace,monospace;padding:2px 6px;background:#f1f5f9;border-radius:4px;font-family:monospace;font-size:13px;}.z{background:#fef08a;}.aa{display:flex;flex-direction:column;margin:0;padding-inline-start:16px;border-left:3px solid #3b82f6;color:#64748b;font-style:italic;}.ab{margin:0;white-space:pre;font-family:ui-monospace,monospace;background:#0f172a;color:#e2e8f0;padding:16px;border-radius:8px;font-family:monospace;font-size:13px;overflow-x:auto;}.ac{display:flex;flex-direction:column;gap:6px;}.ad{display:flex;flex-direction:row;gap:10px;align-items:baseline;}.ae{font-weight:bold;min-width:80px;}.af{color:#64748b;font-style:italic;}.ag{display:flex;flex-direction:row;gap:6px;}.ah{display:flex;flex-direction:column;width:18px;height:18px;border-radius:9px;background:#3b82f6;opacity:0.4;}.ai{display:flex;flex-direction:row;gap:4px;}.aj{display:flex;flex-direction:column;width:24px;height:24px;border-radius:4px;background:#3b82f6;color:white;text-align:center;font-size:12px;font-weight:bold;line-height:24;}.ak{font-weight:bold;min-width:64px;}.al{color:#3b82f6;font-weight:bold;}.am{color:#10b981;font-weight:bold;}.an{display:flex;flex-direction:column;padding:12px;border-radius:6px;background:#3b82f6;color:white;}.an::before{content:"→ ";font-weight:bold;}.ao{font-family:ui-monospace,monospace;}.ap{display:flex;flex-direction:column;gap:10px;max-width:420px;}.aq{font-weight:bold;font-size:13px;}.ar{padding:10px;border:1px solid #e5e7eb;border-radius:6px;transition:border 0.15s ease;}.ar:focus{border:1px solid #3b82f6;}.ar:valid{border:1px solid #10b981;}.ar:invalid{border:1px solid #ef4444;}.as{padding:10px;border:1px solid #e5e7eb;border-radius:6px;}.at{display:flex;flex-direction:row;gap:8px;}.au{padding:10px 16px;background:#3b82f6;color:white;font-weight:bold;border-radius:6px;border:0 solid currentColor;transition:background 0.15s ease;cursor:pointer;}.au:hover{background:#3575dd;}.au:active{background:#2f68c5;}.av{padding:10px 16px;background:white;border:1px solid #e5e7eb;border-radius:6px;cursor:pointer;}.aw{display:flex;flex-direction:row;gap:16px;flex-wrap:wrap;}.ax{display:flex;flex-direction:column;flex:1;min-width:0;gap:8px;min-width:240px;}.ay{margin:0;padding-left:0;list-style:none;gap:4px;}.az{display:flex;flex-direction:column;}.ba{margin:0;padding-left:0;list-style:none;}.bb{text-align:left;padding:8px;}.bc{text-align:right;padding:8px;}.bd{padding:8px;border-top:1px solid #e5e7eb;}.be{padding:8px;border-top:1px solid #e5e7eb;text-align:right;}.bf{display:flex;flex-direction:column;margin:0;gap:6px;}.bg{border-radius:8px;}.bh{color:#64748b;font-size:13px;text-align:center;}.bi{display:flex;flex-direction:column;padding:12px;border:1px solid #e5e7eb;border-radius:6px;background:#f8fafc;}.bj{font-weight:bold;cursor:pointer;}.bk{margin:0;color:#64748b;line-height:1.6;padding-block-start:6px;}.bl{display:flex;flex-direction:column;display:grid;grid-template-columns:1fr 2fr;grid-template-areas:"h h" "s m" "f f";gap:8px;padding:8px;background:#f8fafc;border-radius:8px;}.bm{display:flex;flex-direction:column;grid-area:h;padding:10px;background:#3b82f6;color:white;border-radius:6px;text-align:center;}.bn{display:flex;flex-direction:column;grid-area:s;padding:10px;background:white;border-radius:6px;border:1px solid #e5e7eb;}.bo{display:flex;flex-direction:column;grid-area:m;padding:10px;background:white;border-radius:6px;border:1px solid #e5e7eb;}.bp{display:flex;flex-direction:column;grid-area:f;padding:10px;background:#0f172a;color:white;border-radius:6px;text-align:center;}.bq{gap:4px;font-style:normal;}.br{color:#3b82f6;}.bs{font-size:13px;color:#64748b;}.bt{font-size:13px;}.bu{display:flex;flex-direction:column;padding-block-start:24px;margin-block-start:24px;border-top:1px solid #e5e7eb;gap:8px;}.bv{display:flex;flex-direction:row;gap:8px;align-items:center;}.bw{display:flex;flex-direction:column;padding:12px 20px;background:#3b82f6;color:white;font-weight:bold;border-radius:8px;transition:all 0.15s ease;cursor:pointer;}.bw:hover{background:#3575dd;}.bw:active{background:#2f68c5;}.bx{color:#3b82f6;}.bx:hover{text-decoration:underline;}.bx:visited{color:#8b5cf6;}.by{display:flex;flex-direction:column;flex:1;min-width:0;}.bz{color:#64748b;font-size:13px;}@media(prefers-color-scheme:dark){.a{background:#0b1220;color:#e2e8f0;}.i{color:white;}}@media print{.bu{display:none;}}}@keyframes fade-up{from{opacity:0;transform:translateY(8px);}to{opacity:1;transform:translateY(0);}}</style></head><body><noscript><style>.needs-js{display:none}</style></noscript><div class="a"><header class="b"><nav class="c"><div class="d"><a href="/" class="e">Home</a><span>/</span><a href="/demos" class="e">Demos</a><span>/</span><span class="f">htmlang</span></div></nav><div class="g"><div class="h"><span class="i">Welcome to htmlang</span><p class="j">A minimalist layout language that compiles to <span class="k">static HTML</span> — no JS, no build step. Visit the <a href="https://github.com" rel="noopener noreferrer" target="_blank" class="l">repo</a> for more.</p></div><img src="https://picsum.photos/72" class="m" alt="&quot;Avatar&quot;" fetchpriority="high"></div></header><hr class="n"><section class="o"><span class="p">Features</span><div class="q"><article class="r"><div class="s"><span class="t">✦</span><span class="u">Simple</span></div><span>Write layouts without CSS classes.</span></article><article class="r"><div class="s"><span class="t">⚡</span><span class="u">Fast</span></div><span>Compiles to a single self-contained HTML file.</span></article><article class="r"><div class="s"><span class="t">○</span><span class="u">Minimal</span></div><span>Zero runtime JavaScript by default.</span></article><article class="r"><div class="s"><span class="t">◆</span><span class="u">Typed</span></div><span>LSP with diagnostics and go-to-definition.</span></article></div></section><section class="o"><span class="p">Typography</span><p class="v">A quick brown fox jumps over <span class="w">the lazy</span> <span class="x">dog</span>. Press <kbd class="y">Ctrl+K</kbd> to search. <mark class="z">Highlighted</mark> uses mark. <abbr title="HyperText Markup Language + language">htmlang</abbr> is an abbreviation.</p><blockquote class="aa"><span>Layout is code. Style is code. Everything should compose.</span><cite>— Anonymous</cite></blockquote><pre class="ab">@fn button $label
2+ @el [padding 12, background blue]
3+ @text $label</pre></section><section class="o"><span class="p">Control flow</span><div class="ac"><div class="ad"><span class="ae">Alice</span><span class="e">Engineer</span></div><div class="ad"><span class="ae">Bob</span><span class="e">Designer</span></div><div class="ad"><span class="ae">Carol</span><span class="e">PM</span></div></div><span class="af" data-state="">(Nothing — @each ... @else fallback)</span><div class="ag"><div class="ah"></div><div class="ah"></div><div class="ah"></div><div class="ah"></div><div class="ah"></div><div class="ah"></div></div><div class="ai"><div class="aj"><span>1</span></div><div class="aj"><span>2</span></div><div class="aj"><span>3</span></div><div class="aj"><span>4</span></div><div class="aj"><span>5</span></div><div class="aj"><span>6</span></div></div><div class="d"><span class="ak">Count:</span><span class="al">3 items</span></div><span class="am">✓ Ready</span><div class="an"><span>Conditional styling via <code class="ao">if(cond, a, b)</code>.</span></div></section><section class="o"><span class="p">Forms</span><form action="/subscribe" class="ap"><label class="aq" for="email">Email</label><input class="ar" id="email" type="email" name="email" placeholder="you@example.com" required><label class="aq" for="role">Role</label><select class="as" id="role" name="role"><option value="dev">Developer</option><option value="designer">Designer</option><option value="other">Other</option></select><label class="aq" for="msg">Message</label><textarea class="as" id="msg" name="msg" rows="3"></textarea><div class="at"><button class="au" type="submit">Subscribe</button><button class="av" type="reset">Reset</button></div><progress value="60" max="100"></progress></form></section><section class="o"><span class="p">Data</span><div class="aw"><div class="ax"><span class="w">Unordered</span><ul class="ay"><li class="az">Composable with @each</li><li class="az">Indent to nest children</li><li class="az">Bold list items work too</li></ul><span class="w">Ordered</span><ol class="ba"><li class="az">First</li><li class="az">Second</li><li class="az">Third</li></ol></div><div class="ax"><span class="w">Table</span><table><thead><tr><th class="bb">Item</th><th class="bc">Qty</th></tr></thead><tbody><tr><td class="bd">Widgets</td><td class="be">12</td></tr><tr><td class="bd">Gadgets</td><td class="be">7</td></tr></tbody></table></div></div><figure class="bf"><img src="https://picsum.photos/640/200" class="bg" alt="&quot;A random placeholder&quot;" fetchpriority="high"><figcaption class="bh">A placeholder image.</figcaption></figure></section><section class="o"><span class="p">Disclosure + grid areas</span><details class="bi"><summary class="bj">What is htmlang?</summary><p class="bk">htmlang is a layout-first language that compiles to a single, self-contained HTML file with embedded CSS.</p></details><div class="bl"><div class="bm"><span>Header</span></div><div class="bn"><span>Sidebar</span></div><div class="bo"><span>Main</span></div><div class="bp"><span>Footer</span></div></div></section><section class="o"><span class="p">Misc</span><address class="bq"><span class="w">htmlang HQ</span><span>123 Flexbox Avenue</span><a href="mailto:hi@htmlang.dev" class="br">hi@htmlang.dev</a></address><div class="s"><span class="bs">Published</span><time datetime="2026-04-16" class="bt" datetime="2026-04-16">April 16 2026</time></div><div class="s"><span class="bs">Confidence</span><meter value="8" min="0" max="10" low="3" high="7"></meter></div></section><footer class="bu"><div class="bv"><div class="bw"><a href="https://github.com" rel="noopener noreferrer" target="_blank">Get Started</a></div><a href="https://github.com" rel="noopener noreferrer" target="_blank" class="bx">Browse source</a><div class="by"></div><span class="bz">© 2026 htmlang</span></div></footer></div></body></html>
examples/demo.html.map+1−1
@@ -1 +1 @@
1−{"version":3,"file":"demo.html","sourceRoot":"","sources":["demo.hl"],"names":[],"mappings":"AAgBA;AACA;AACA;AACA;AACA;AAGA;AAXA;AACA;AAcA;AArBA;AACA;AADA;AACA;AADA;AACA;AA6BA;AACA;AAAA;AACA;AACA;AACA"}
1+{"version":3,"file":"demo.html","sourceRoot":"","sources":["demo.hl"],"names":[],"mappings":"AA4DA;AAWA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAIA;AAEA;AAlCA;AACA;AAqCA;AA9CA;AACA;AACA;AACA;AAHA;AACA;AACA;AACA;AAHA;AACA;AACA;AACA;AAHA;AACA;AACA;AACA;AAKA;AACA;AAiDA;AAQA;AAKA;AAEA;AAjEA;AACA;AA6EA;AAEA;AACA;AACA;AAFA;AACA;AACA;AAFA;AACA;AACA;AAOA;AAGA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AACA;AAMA;AAQA;AAQA;AApIA;AACA;AA6IA;AACA;AACA;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AASA;AAKA;AAlLA;AACA;AAqLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AApNA;AACA;AAwNA;AACA;AACA;AAKA;AAOA;AAEA;AAEA;AAEA;AA7OA;AACA;AAiPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAKA;AACA;AAAA;AAQA;AAKA;AACA"}