3A minimalist layout language inspired by elm-ui that compiles to static HTML.
7- `@` means structure, bare lines mean content
8- Layout is explicit and compositional — no CSS cascade
9- Every element declares its own layout role
10- Output is a self-contained HTML file with embedded CSS (flexbox)
14| Element | Output | Purpose |
15|--------------|------------------|--------------------------------|
16| `@row` | flex row | Horizontal layout |
17| `@column` | flex column | Vertical layout |
18| `@el` | div | Generic container |
19| `@text` | span | Styled inline text |
20| `@paragraph` | p with spans | Flowing/wrapping inline text |
21| `@image` | img | Image |
22| `@link` | a | Anchor wrapping children |
23| `@raw` | verbatim HTML | Escape hatch |
24| `@nav` | nav | Navigation landmark |
25| `@header` | header | Page/section header |
26| `@footer` | footer | Page/section footer |
27| `@main` | main | Main content area |
28| `@section` | section | Thematic section |
29| `@article` | article | Self-contained content |
30| `@aside` | aside | Sidebar/tangential content |
31| `@list` | ul/ol | List (`[ordered]` for ol) |
32| `@item` | li | List item |
33| `@table` | table | Table |
34| `@thead` | thead | Table head group |
35| `@tbody` | tbody | Table body group |
36| `@tr` | tr | Table row |
37| `@td` | td | Table cell |
38| `@th` | th | Table header cell |
39| `@video` | video | Video element |
40| `@audio` | audio | Audio element |
41| `@form` | form | Form container |
42| `@details` | details | Disclosure widget |
43| `@summary` | summary | Summary for `@details` |
44| `@blockquote`| blockquote | Block quotation |
45| `@cite` | cite | Citation/source reference |
46| `@code` | code | Inline code (monospace) |
47| `@pre` | pre | Preformatted text |
48| `@hr` | hr | Horizontal rule (self-closing) |
49| `@figure` | figure | Figure with optional caption |
50| `@figcaption`| figcaption | Caption for `@figure` |
51| `@progress` | progress | Progress bar |
52| `@meter` | meter | Meter/gauge element |
53| `@iframe` | iframe | Embedded external page |
54| `@output` | output | Form calculation result |
55| `@canvas` | canvas | Drawing surface for scripts |
57| `@script` | script | JavaScript (inline or external) |
58| `@noscript` | noscript | Fallback when JS is disabled |
59| `@address` | address | Contact information |
60| `@search` | search | Search landmark (HTML5) |
61| `@breadcrumb` | nav>ol | Semantic breadcrumb navigation |
63Bare lines (not starting with `@` or `[`) are text nodes.
74Children are indented under their parent. Attributes are optional, comma-separated inside `[...]`. Attribute lists can span multiple lines:
81 shadow 0 2px 4px rgba(0,0,0,0.1)
98 shadow 0 2px 4px rgba(0,0,0,0.05)
103@column [max-width 800, center-x, padding 40, spacing $gap]
105 @column [width fill, spacing 10]
106 @text [bold, size 32] Welcome
107 @paragraph [line-height 1.6]
108 This is a page built with {@text [bold, color $primary] htmlang}.
109 Read the {@link https://docs.example.com docs} to learn more.
110 @image [width 80, height 80, rounded 40] avatar.png
113 @row [wrap, spacing 10]
116 [$card, background #f9fafb]
121 @el [padding 16, background $primary, rounded 8] > @link https://example.com
122 @text [color white] Get Started
124 @text [color #888, text-align right] © 2026
127 <canvas id="chart"></canvas>
135Sets the HTML `<title>` and generates boilerplate (`<!DOCTYPE>`, `<html>`, `<head>`, `<body>`).
143Defines a variable. Referenced with `$name`.
149@el [background $primary, spacing $gap]
152Quoted values support string interpolation:
156@let greeting "Hello $name" -- "Hello World"
158@let url "$base/users" -- "/api/users"
163Inlines another `.hl` file. The path is resolved relative to the current file. Variables defined with `@let`, attribute bundles from `@define`, and functions from `@fn` in the included file are available after the `@include` line.
167@include components/card.hl
170Variables can be used in the filename:
174@include $component.hl
177Circular includes are detected and reported as errors. Nested includes are supported.
181Like `@include`, but only imports definitions (`@let`, `@define`, `@fn`) without emitting DOM nodes. Use this for shared theme/component libraries.
184@import theme.hl -- imports variables, defines, functions only
185@include header.hl -- inlines everything including DOM nodes
190Loads a JSON file and makes its values available as template variables. Useful for data-driven static sites.
193@data site.json -- top-level object keys become variables
194@data $posts data/posts.json -- load with a prefix
201 "tags": ["rust", "html", "css"],
203 {"label": "Home", "url": "/"},
204 {"label": "About", "url": "/about"}
209Without prefix (`@data site.json`):
210- `$title` → `"My Site"`
211- `$tags` → iterable with `@each`
212- `$links` → destructurable: `@each $label, $url in $links`
214With prefix (`@data $site site.json`):
215- `$site.title` → `"My Site"`
216- `$site.tags` → iterable
217- `$site.links` → destructurable
219Arrays of objects are automatically formatted for `@each` destructuring. Indexed access is also available: `$links.0.label`, `$links.1.url`, etc. The count is available as `$links._count`.
223Adds a `<meta>` tag to the document `<head>`. Requires `@page`.
226@meta description A portfolio site
227@meta og:image https://example.com/preview.png
232Adds raw content to the document `<head>`. Use for external fonts, favicons, or custom CSS/JS.
236 <link rel="icon" href="favicon.ico">
237 <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter">
242Creates a named attribute bundle. Referenced with `$name` inside attribute lists.
245@define card [padding 20, background white, rounded 8, border 1 #e5e7eb]
249@el [$card, background #f9fafb]
250 Overridden background
253Attributes listed after `$name` override those in the definition.
257Creates a composable style group. Like `@define`, but intended for reusable style patterns. Referenced with `...$name` (spread syntax) or `$name` inside attribute lists.
260@mixin card-style [padding 20, rounded 8, background white]
261@mixin interactive [cursor pointer, hover:background #e5e7eb, transition all 0.15s ease]
263@el [...$card-style, ...$interactive, border 1 #ccc]
264 Composed styles from two mixins
269Compile-time assertion. If the condition is false, a compile error is emitted. Useful for enforcing design system constraints.
275@assert $spacing == 16
276@assert $primary != red
281Defines a pure function (reusable component). Parameters are prefixed with `$`. Default values can be specified with `=`.
284@fn card $title $variant=primary
285 @el [padding 20, background white, rounded 8, border 1 #e5e7eb]
286 @text [bold, size 18] $title
290Call it like any element, passing parameters in `[...]`:
293@card [title Hello World]
294 This is the card body.
295 @text [italic] With styled text.
297@card [title Warning, variant danger]
301Parameters with defaults can be omitted in calls — the default value is used.
305A slot inside a function body that expands to the caller's indented children.
309 @column [max-width 800, center-x, padding 40]
310 @text [bold, size 32] $title
313@layout [title My Page]
318Functions can call other functions. `@let` and `@define` variables are available inside function bodies. Function parameters shadow `@let` variables of the same name within the body.
324Any line not starting with `@` or `[` is a text node.
334Use `@text` when you need attributes.
337@text [bold, size 24, color #333] Hello world
342Use `{...}` to embed elements inside text lines. Essential for mixed-style paragraphs.
346 This is {@text [bold] important} and this is a {@link https://example.com link}.
351`--` starts a comment. The rest of the line is ignored.
356 -- todo: add nav items
361A line starting with `[` (attributes) that has indented children is an anonymous container (implicit `@el`).
364[padding 20, background white]
368@el [padding 20, background white]
372## Single-child chaining
374Use `>` to chain single-child elements on one line, reducing nesting depth.
377@el [padding 16, background blue, rounded 8] > @link https://example.com
378 @text [color white] Get Started
381@el [padding 16, background blue, rounded 8]
382 @link https://example.com
383 @text [color white] Get Started
386The last element in the chain takes the indented children.
390Triple-quoted block pasted verbatim into output. Use for arbitrary HTML, CSS, or JS.
395 @keyframes spin { to { transform: rotate(360deg); } }
397<div class="custom-widget"></div>
403All numeric values default to pixels. You can use CSS units explicitly:
406@el [width 50%, height 100vh, padding 2rem, max-width 80ch, size 1.2em]
409Supported units: `%`, `rem`, `em`, `vh`, `vw`, `vmin`, `vmax`, `dvh`, `svh`, `ch`, `ex`, `cm`, `mm`, `in`, `pt`, `pc`, `fr`.
415Form container. Argument is the `action` URL.
418@form [method post] /submit
419 @label [for email] Email
420 @input [type email, name email, required]
421 @button [type submit] Send
424### `@details` / `@summary`
426Native disclosure widget. Use `[open]` to expand by default.
430 @summary FAQ Question
431 @text The answer is here.
434### `@blockquote` / `@cite`
436Semantic quotation with optional citation.
439@blockquote [padding 20, border-left 4 #ccc]
440 @text To be or not to be
446Code and preformatted text. `@code` renders as `<code>` with monospace font. `@pre` preserves whitespace.
450 @code console.log("hello")
455Horizontal rule / divider (self-closing). Alias: `@divider`.
458@hr [border-top 1 #e5e7eb]
461### `@figure` / `@figcaption`
463Figure with optional caption.
467 @image [alt Sunset, width fill] sunset.jpg
468 @figcaption A beautiful sunset
471### `@progress` / `@meter`
473Progress bar and meter elements. Use `value`, `max`, `min` attributes.
476@progress [value 70, max 100]
477@meter [value 6, min 0, max 10, low 3, high 8]
480## `@each` destructuring
482When `@each` has more than one variable and items contain spaces, values are destructured:
485@each $name, $url in Home /, About /about, Contact /contact
489`var()` and `calc()` expressions are also passed through as-is.
491## `@each` with `@else`
493When the list is empty, the `@else` block is rendered as a fallback:
499 @text [color #888] No items found.
504Embedded external page. Argument is the `src` URL.
507@iframe [width fill, height 400, sandbox] https://example.com
510Attributes: `sandbox`, `allow`, `allowfullscreen`, `referrerpolicy`.
514Drawing surface for JavaScript. Use with `@raw` for scripts.
517@canvas [width 400, height 300, id chart]
522Form output element for displaying calculation results.
525@output [for a b] Result
530Prefix any style attribute with `before:` or `after:` to apply it to the `::before` or `::after` pseudo-element. Use with `content` to set the generated content.
533@el [before:content "→ ", before:color red, before:font-weight bold]
534 Item with arrow prefix
536@el [after:content " ✓", after:color green]
540Content values are automatically quoted unless they are CSS keywords (`none`, `normal`) or CSS functions (`attr()`, `counter()`).
542## Conditional attribute values
544Use `if(condition, true_value, false_value)` inside attribute values for conditional styling:
550@el [background if($active, blue, gray)]
553@el [color if($theme == dark, white, black)]
557Supports equality (`==`), inequality (`!=`), and truthy checks.
559## Attributes reference
561### Layout (set on parent)
563| Attribute | Effect |
564|------------------------|----------------------------------|
565| `spacing N` | Gap between children |
566| `gap N` | Alias for `spacing` |
567| `gap-x N` | Horizontal gap (column-gap) |
568| `gap-y N` | Vertical gap (row-gap) |
569| `padding N` | Uniform padding |
570| `padding Y X` | Vertical + horizontal padding |
571| `padding T H B` | Top + horizontal + bottom |
572| `padding T R B L` | Per-side padding |
573| `padding-x N` | Horizontal padding |
574| `padding-y N` | Vertical padding |
576### Sizing (set on child)
578| Attribute | Effect |
579|------------------------|----------------------------------|
580| `width fill` | Take remaining space (flex: 1) |
581| `width N` | Exact pixels |
582| `width shrink` | Fit to content (default) |
583| `height fill` | Take remaining space |
584| `height N` | Exact pixels |
585| `height shrink` | Fit to content (default) |
586| `min-width N` | Minimum width |
587| `max-width N` | Maximum width |
588| `min-height N` | Minimum height |
589| `max-height N` | Maximum height |
591### Alignment (set on child)
593| Attribute | Effect |
594|------------------------|----------------------------------|
595| `center-x` | Center horizontally |
596| `center-y` | Center vertically |
597| `align-left` | Align to left |
598| `align-right` | Align to right |
599| `align-top` | Align to top |
600| `align-bottom` | Align to bottom |
604| Attribute | Effect |
605|------------------------|----------------------------------|
606| `background COLOR` | Background color |
607| `color COLOR` | Text color |
608| `border N COLOR` | Border width and color |
609| `border-top N COLOR` | Top border |
610| `border-bottom N COLOR`| Bottom border |
611| `border-left N COLOR` | Left border |
612| `border-right N COLOR` | Right border |
613| `rounded N` | Border radius |
614| `shadow VALUE` | Box shadow (CSS value) |
615| `bold` | Bold text |
616| `italic` | Italic text |
617| `underline` | Underlined text |
618| `size N` | Font size in px |
619| `font NAME` | Font family |
620| `text-align VALUE` | Text alignment (left/center/right/justify) |
621| `line-height VALUE` | Line height (unitless or px) |
622| `letter-spacing N` | Letter spacing |
623| `text-transform VALUE` | Transform (uppercase/lowercase/capitalize) |
624| `white-space VALUE` | White-space (nowrap/pre/normal) |
625| `transition VALUE` | CSS transition |
626| `cursor VALUE` | Cursor style |
627| `opacity VALUE` | Opacity (0–1) |
628| `overflow VALUE` | Overflow (hidden/scroll/auto/visible) |
629| `position VALUE` | Position (relative/absolute/fixed/sticky) |
630| `top N` | Top offset (positioned elements) |
631| `right N` | Right offset |
632| `bottom N` | Bottom offset |
633| `left N` | Left offset |
634| `z-index N` | Stack order |
635| `display VALUE` | Display mode (none/block/flex/grid) |
636| `visibility VALUE` | Visibility (visible/hidden) |
637| `transform VALUE` | CSS transform (e.g., rotate(45deg)) |
638| `backdrop-filter VALUE`| Backdrop filter (e.g., blur(10px)) |
642| Attribute | Effect |
643|------------------------|----------------------------------|
644| `margin N` | Uniform margin |
645| `margin Y X` | Vertical + horizontal margin |
646| `margin T R B L` | Per-side margin |
647| `margin-x N` | Horizontal margin |
648| `margin-y N` | Vertical margin |
652| Attribute | Effect |
653|------------------------|----------------------------------|
654| `filter VALUE` | CSS filter (blur, brightness) |
655| `object-fit VALUE` | Object fit (cover/contain/fill) |
656| `object-position VALUE`| Object position within container|
657| `text-shadow VALUE` | Text shadow |
658| `text-overflow VALUE` | Text overflow (ellipsis/clip) |
659| `pointer-events VALUE` | Pointer events (none/auto) |
660| `user-select VALUE` | User selection (none/text/all) |
661| `justify-content VALUE`| Main axis alignment |
662| `align-items VALUE` | Cross axis alignment |
663| `order N` | Flex/grid item order |
664| `background-size VALUE`| Background size |
665| `background-position VALUE`| Background position |
666| `background-repeat VALUE`| Background repeat |
667| `word-break VALUE` | Word break (break-all/keep-all) |
668| `overflow-wrap VALUE` | Overflow wrap (break-word) |
669| `font-weight VALUE` | Font weight (100-900/bold/lighter)|
670| `font-style VALUE` | Font style (normal/italic/oblique)|
671| `text-wrap VALUE` | Text wrapping (balance/pretty) |
672| `will-change VALUE` | Performance hint (transform) |
673| `touch-action VALUE` | Touch behavior (none/pan-x) |
674| `vertical-align VALUE` | Vertical alignment (middle/top) |
675| `contain VALUE` | CSS containment (layout/paint) |
676| `content-visibility VALUE` | Lazy rendering (auto) |
677| `scroll-margin N` | Scroll margin (for anchors) |
678| `scroll-padding N` | Scroll padding (scroll-snap) |
679| `content VALUE` | Pseudo-element content (with before:/after:)|
683Prefix any style attribute with `hover:`, `active:`, or `focus:` to apply it on that state.
686@el [padding 16, background #3b82f6, hover:background #2563eb, active:background #1d4ed8, rounded 8, transition all 0.15s ease]
687 @text [color white] Click me
690All style attributes support state prefixes: `hover:color`, `active:rounded`, `focus:border`, etc.
694Prefix any style attribute with `dark:` to apply it when the user's system is in dark mode.
697@el [background white, dark:background #1a1a2e, color #333, dark:color #eee]
698 @text Theme-aware content
701This generates a `@media (prefers-color-scheme: dark)` rule.
705Prefix any style attribute with `print:` to apply it when printing.
708@nav [print:display none]
709 @text Navigation (hidden in print)
712This generates a `@media print` rule.
716| Attribute | Effect |
717|------------------------|----------------------------------|
718| `wrap` | Enable flex-wrap (on `@row`) |
719| `grid` | Enable CSS grid layout |
720| `grid-cols N` | Grid template columns (N equal) |
721| `grid-rows N` | Grid template rows (N equal) |
722| `col-span N` | Span N columns in grid |
723| `row-span N` | Span N rows in grid |
727| Attribute | Effect |
728|------------------------|----------------------------------|
729| `id NAME` | HTML id attribute |
730| `class NAME` | HTML class attribute |
734| Attribute | Effect |
735|------------------------|----------------------------------|
736| `color-scheme VALUE` | Color scheme (`light`, `dark`, `light dark`) |
737| `appearance VALUE` | Form element appearance (`none`) |
741Use HTML Popover API attributes for declarative popovers without JavaScript.
744@button [popovertarget info-panel] Show Info
745@el [popover, id info-panel, padding 20, background white, rounded 8]
746 @text This is a popover
749| Attribute | Effect |
750|-------------------------------|---------------------------------|
751| `popover` | Make element a popover |
752| `popovertarget ID` | Open popover with given ID |
753| `popovertargetaction VALUE` | Action (toggle/show/hide) |
757| Attribute | Effect |
758|------------------------|----------------------------------|
759| `inputmode VALUE` | Virtual keyboard type (numeric/email/search/tel/url) |
760| `enterkeyhint VALUE` | Enter key label (enter/done/go/next/previous/search/send) |
761| `fetchpriority VALUE` | Resource priority (high/low/auto) |
762| `translate VALUE` | Whether to translate (yes/no) |
763| `spellcheck VALUE` | Spell check (true/false) |
767SVG images can be inlined directly into the HTML output using the `[inline]` attribute:
770@image [inline, width 24, height 24] icon.svg
773This reads the SVG file and embeds its content directly, keeping the output self-contained.
778htmlang init # scaffold a new project
779htmlang init my-site # scaffold in a new directory
780htmlang new about-us # create about-us.hl from template
781htmlang page.hl # compile page.hl → page.html
782htmlang site/ # compile all .hl files in directory
783htmlang --watch page.hl # compile and watch for changes
784htmlang -w page.hl # short form
785htmlang --serve site/ # serve a multi-page site with hot reload
786htmlang -s --open site/ # serve and open browser
787htmlang check page.hl # check for errors without writing output
788htmlang check src/ # check all .hl files in a directory
789htmlang convert page.html # convert HTML to .hl format (stdout)
790htmlang build src/ -o dist/ # parallel compile + copy static assets
791htmlang --compat page.hl # compile with vendor prefixes
792htmlang --format json page.hl # output diagnostics as JSON
793htmlang lint --format json src/ # lint with JSON output
794htmlang dead-code --format json src/ # dead code report as JSON
795htmlang lint page.hl # stricter lint checks (accessibility, nesting)
796htmlang lint src/ # lint all .hl files in a directory
797htmlang stats page.hl # show file statistics (elements, CSS, colors)
798htmlang repl # interactive REPL (type .hl, get HTML)
799htmlang feed src/ # generate RSS feed from @page metadata
800htmlang feed src/ -b https://mysite.com # with custom base URL
801htmlang components src/ # list all @fn definitions across project
802htmlang deps src/ # show dependency graph (@include/@import)
803htmlang dead-code src/ # find unused @fn, @define, @let across project
804htmlang deploy src/ # build and deploy to GitHub Pages
805htmlang playground # generate self-contained HTML playground
806htmlang clean src/ # remove generated .html files
807htmlang outline page.hl # show document structure tree
810Watch mode recompiles automatically when the source file or any `@include`d/`@import`ed files change.
812The `build` command automatically extracts shared CSS rules across pages into a `shared.css` file when outputting to a directory.
816Each `.hl` file compiles to a single self-contained `.html` file:
818- Elements map to `<div>`, `<span>`, `<p>`, `<a>`, `<img>` as appropriate
819- Layout uses flexbox (`display: flex`, `flex-direction`, `gap`, etc.)
820- Styles are scoped via generated class names in an embedded `<style>` block
821- No external CSS, no JavaScript (unless injected via `@raw`)
822- `@page` generates the HTML boilerplate; without it, output is an HTML fragment
824## Template inheritance (`@extends`)
826A page can inherit a base layout and fill named `@slot` blocks:
831@column [max-width 800, center-x, padding 40]
833 @text [bold, size 32] Default Header
836 @text [color #888] Default Footer
843 @text [bold, size 32] About Us
845 @paragraph We are a team of...
848Slots not filled by the extending page use the default children from the layout.
850## Design tokens (`@theme`)
852Centralized design token definitions. Each token becomes both a `$variable` and a `--css-custom-property`:
860 font-body system-ui, sans-serif
866@let --primary #3b82f6
867@let secondary #10b981
868@let --secondary #10b981
872## Deprecation (`@deprecated`)
874Mark a function as deprecated. Callers receive a compile-time warning:
877@deprecated Use @card-v2 instead
884When `@old-card` is called, the compiler emits: `warning: @old-card is deprecated: Use @card-v2 instead`
888Color manipulation via variable filters:
893@el [background $primary|lighten:20] -- 20% lighter
894@el [background $primary|darken:10] -- 10% darker
895@el [background $primary|alpha:0.5] -- 50% transparent (#3b82f67f)
896@el [background $primary|mix:#ffffff:50] -- 50% mixed with white
899Filters: `lighten:N` (0-100), `darken:N` (0-100), `alpha:N` (0-1), `mix:COLOR:N` (0-100).
901## Enhanced `@keyframes`
903Keyframes support htmlang attribute syntax:
911 0% [transform translateX(-100%)]
912 50% [transform translateX(0), opacity 1]
913 100% [transform translateX(100%), opacity 0]
916Raw CSS syntax is also supported for backwards compatibility.
918## Additional attributes
920| Attribute | Effect |
921|-----------|--------|
922| `autofocus` | Auto-focus element on page load (boolean) |
926Use CSS Grid's named template areas with the `grid-template-areas` and `grid-area` attributes:
929@el [grid, grid-template-areas "header header" "sidebar main" "footer footer", gap 20]
930 @el [grid-area header, padding 10, background #3b82f6]
932 @el [grid-area sidebar, padding 10]
934 @el [grid-area main, padding 10]
936 @el [grid-area footer, padding 10]
942The `animate` attribute is shorthand for the CSS `animation` property:
949@el [animate fade-in 0.3s ease]
955The `view-transition-name` attribute enables the View Transitions API for smooth page transitions:
958@el [view-transition-name hero]
959 Hero content that transitions between pages
962## `:has()` pseudo-selector
964Style elements based on their children using the `has()` prefix:
967@el [padding 20, has(.active):background #dbeafe, has(img):padding 0]
971Generates CSS `:has()` selectors: `.class:has(.active) { background:#dbeafe; }`
975Variables support arithmetic expressions. The `=` sign is optional:
979@let large = $base * 2 -- 32
980@let gap $base + 4 -- 20 (= is optional)
983Supported operators: `+`, `-`, `*`, `/`.
985## Named slots in `@fn`
987Functions support named `@slot` blocks for multi-region components:
991 @column [max-width 800, center-x, padding 40]
993 @text [bold, size 32] $title
996 @text [color #888] Default Footer
998@layout [title My Page]
1000 @text [bold, size 32] Custom Header
1002 @paragraph Main content here
1005Slots not filled by the caller use the default children from the function definition.
1011Embeds JavaScript. Supports inline code and external files via `src`. Children are raw JS (not HTML-escaped).
1014@script [src app.js, defer]
1017 console.log("hello world");
1018 document.addEventListener("DOMContentLoaded", () => {
1023Attributes: `src`, `type`, `defer`, `async`, `crossorigin`, `integrity`, `nomodule`.
1027Fallback content displayed when JavaScript is disabled.
1031 @text This page requires JavaScript.
1036Contact information, rendered as `<address>`.
1040 @text [bold] John Doe
1041 @link mailto:john@example.com john@example.com
1046HTML5 `<search>` landmark for search functionality.
1050 @input [type search, placeholder Search...]
1051 @button [type submit] Search
1056Semantic breadcrumb navigation. Generates `<nav aria-label="breadcrumb">` with an `<ol>` list. Each child becomes an `<li>`.
1059@breadcrumb [spacing 10]
1061 @link /docs Documentation
1069Sets the canonical URL. Generates `<link rel="canonical">` in the document head.
1072@canonical https://example.com/my-page
1077Sets the base URL for relative links. Generates `<base href="...">`.
1080@base https://example.com/
1085Declares a custom font. Generates a CSS `@font-face` rule with `font-display: swap`. Format is auto-detected from the file extension.
1088@font-face Inter fonts/inter.woff2
1089@font-face Mono fonts/jetbrains-mono.ttf
1094Structured data for SEO. Generates a `<script type="application/ld+json">` block. Indented body is raw JSON.
1099 "@context": "https://schema.org",
1105## Additional pseudo-states
1107| Prefix | CSS Selector | Purpose |
1108|--------|--------------|---------|
1109| `visited:` | `:visited` | Visited links |
1110| `empty:` | `:empty` | Empty elements |
1111| `target:` | `:target` | URL fragment target |
1112| `valid:` | `:valid` | Valid form inputs |
1113| `invalid:` | `:invalid` | Invalid form inputs |
1116@link [visited:color purple] https://example.com
1119@input [type email, valid:border 2 green]
1120@el [target:background yellow, id section-1]
1121 Highlighted when navigated to
1124## Additional CSS properties
1126| Attribute | Effect |
1127|-----------|--------|
1128| `text-underline-offset N` | Offset of text underline from text |
1129| `column-width N` | Ideal column width for multi-column layout |
1130| `column-rule VALUE` | Rule between columns (e.g., `1px solid #ccc`) |
1133@text [underline, text-underline-offset 4, text-decoration-thickness 2]
1136@el [column-count 3, column-width 200, column-rule 1px solid #ccc]
1137 Multi-column content
1140## CSS `@layer` wrapping
1142Generated styles are wrapped in `@layer htmlang { ... }` for specificity management. This allows `@style` blocks and `@raw` CSS to easily override generated styles without specificity wars.
1148Show the file dependency graph (`@include`, `@import`, `@extends` relationships):
1154### `htmlang dead-code`
1156Find unused `@fn`, `@define`, and `@let` definitions across an entire project:
1159htmlang dead-code src/
1164Build and deploy to GitHub Pages:
1170Compiles all `.hl` files, copies static assets, and pushes to a `gh-pages` branch.
1174Remove generated `.html` files from a directory (matching `.hl` source files). Also removes `sitemap.xml` if present.
1178htmlang clean # clean current directory
1181### `htmlang outline`
1183Show the document structure tree — a quick overview of elements and nesting without compiling.
1186htmlang outline page.hl
1189### `htmlang playground`
1191Generate a self-contained HTML playground for experimenting with htmlang:
1194htmlang playground # writes playground.html
1195htmlang playground my-play.html # custom output path
1196htmlang clean src/ # remove generated .html files
1197htmlang outline page.hl # show document structure tree
1202A VS Code extension is available in `editors/vscode/` with:
1204- Syntax highlighting via TextMate grammar
1205- LSP integration via `htmlang-lsp` for:
1206 - Real-time diagnostics and error checking
1207 - Completions for elements, attributes, variables, and functions
1208 - Hover documentation for all elements and attributes
1209 - Go to definition for variables, defines, and functions
1210 - Find all references for variables and functions
1211 - Rename refactoring for variables and functions
1212 - Signature help for `@fn` parameters
1213 - Document formatting (format on save)
1214 - Code actions (quick-fixes for typos, unused variables, missing attributes)
1215 - Auto-import suggestions (scans project for `@fn` definitions)
1216 - Extract selection to `@fn` refactoring
1217 - Color picker for hex colors
1218 - Code folding and document symbols
1219 - Semantic tokens for syntax highlighting
1220 - VS Code snippets for common patterns (`@fn`, `@each`, `@grid`, `@form`, etc.)
1222## Additional directives reference
1224The compiler recognizes a number of directives that are documented only briefly
1225above. A concise reference:
1227### Content generation
1229- `@markdown` — indented body is parsed as Markdown and emitted as HTML.
1230- `@raw """..."""` — embed verbatim HTML / CSS / JS.
1231- `@svg path/to/icon.svg` — inline an SVG file's contents.
1232- `@fetch url -> $name` — fetch a JSON payload at build time and bind it.
1233- `@data name path.json` — load a JSON file for iteration with `@each`.
1237- `@lang en` — set `<html lang>`.
1238- `@favicon /favicon.png` — inject a favicon link.
1239- `@meta name value` — add a `<meta>` tag.
1240- `@og key value` — add an Open Graph `<meta property="og:key">` tag.
1241- `@canonical https://…` — set `<link rel="canonical">`.
1242- `@base /base/path/` — set `<base href>`.
1243- `@manifest [Name]` — emit a PWA `manifest.json` reference and body.
1244- `@breakpoint name width` — register a custom responsive prefix.
1248- `@style` — indented body is raw CSS injected into `<style>`.
1249- `@scope (selector)` — wrap body in CSS `@scope` for scoped styles.
1250- `@starting-style` — CSS entry-animation starting values.
1251- `@font-face name url` — register a web font.
1252- `@theme` — design tokens emitted as CSS custom properties.
1253- `@keyframes name` — define keyframe animations.
1254- `@css-property name syntax value` — register a typed custom property.
1258- `@if cond` / `@unless cond` / `@else` / `@else if`.
1259- `@match $value` / `@switch $value` — exhaustive branching.
1260- `@each item in list` / `@each item, $_index in list` — iterate.
1261- `@for $i in 0..10 [step 2]` — numeric ranges.
1262- `@repeat N` — repeat a block N times.
1263- `@defer` — defer block rendering below the fold.
1267- `@include file.hl` — paste file contents here.
1268- `@import file.hl` — import @fn / @let / @define (with optional `as` alias).
1269- `@use "file.hl" fn1, fn2` — import a named subset.
1270- `@extends template.hl` — template inheritance; override with `@slot`.
1271- `@layout path.hl` — wrap output in a layout template.
1272- `@collection path/ -> $items` — iterate over a directory.
1274### Functions & composition
1276- `@fn name $p1 $p2` — define a function; body uses `@children` / `@slot`.
1277- `@component name $p` — like `@fn` but emits a scoped wrapper class.
1278- `@mixin name [...attrs]` — attribute bundle you can merge elsewhere.
1279- `@define name [...attrs]` — named attribute preset, used as `[$name]`.
1280- `@with $source as $alias` — temporarily rebind a variable.
1284- `@assert cond [message]` — emit an error if a boolean check fails.
1285- `@warn message` / `@debug expr` / `@log message` — compile-time output.
1286- `@deprecated name [reason]` — mark a function as deprecated.
1287- `@translations locale` — bind i18n strings available as `$t.key`.
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list