Skip to content HtmlpressStatic site generator HtmlpressStatic site generator

Change theme

Keyboard shortcuts

Rich Elements

Updated

A few htmlpress-* elements cover what HTML has no element for. They are light-DOM custom elements, so their content stays plain HTML that reads well even before the script loads. Each one's styles and script are linked only on pages that use it. Put block content (<p>, <h3>, <pre>) inside a component, not bare text.

Tables

A <table> is styled as it is, and one with a <thead> sorts by any header clicked:

<table>
  <thead><tr><th>Language</th><th>Year</th><th>Typing</th></tr></thead>
  <tbody><tr><td>TypeScript</td><td>2012</td><td>Static</td></tr>…</tbody>
</table>
| Language | Year | Typing |
| --- | --- | --- |
| TypeScript | 2012 | Static |

Renders as:

Language Year Typing
TypeScript 2012 Static
Python 1991 Dynamic
Rust 2010 Static
JavaScript 1995 Dynamic

Callouts

Callouts highlight important information. type is info (the default), note, tip, warning or danger, and title replaces the heading the type gives:

<htmlpress-callout><p>This is a note.</p></htmlpress-callout>

<htmlpress-callout type="warning" title="Breaking Change">
  <p>This API has been removed in v2.</p>
</htmlpress-callout>
:::info
This is a note.
:::

:::warning[Breaking Change]
This API has been removed in v2.
:::

Renders as:

This is a note.

Every page built.

Be careful with this.

Never edit .htmlpress/build: every build replaces it.

This API has been removed in v2.

Headings inside a callout stay out of the page's table of contents.

Expandable

No component needed: the theme styles a plain <details>.

<details>
  <summary>Click to expand</summary>
  <p>Hidden content here with <strong>HTML</strong> support.</p>
</details>
:::details[Click to expand]
Hidden content here with **Markdown** support.
:::

Renders as:

Click to expand

Hidden content here with HTML support.

You can nest any HTML inside, including code blocks, lists and callouts:

Configuration example
site: https://htmlpress.dev
title: Htmlpress

Code Tabs

Tabs that hold only code blocks join into one framed block. Each <section> is a tab, named by its title:

<htmlpress-tabs sync="lang">
  <htmlpress-tab title="JavaScript"><pre><code>console.log("hello")</code></pre></htmlpress-tab>
  <htmlpress-tab title="Python"><pre><code>print("hello")</code></pre></htmlpress-tab>
</htmlpress-tabs>
```js tab="JavaScript" sync="lang"
console.log("hello")
```

```python tab="Python"
print("hello")
```

Renders as:

console.log("hello")
print("hello")

Add sync="key" to keep tab groups in sync, as described under Content Tabs below.

Content Tabs

Group arbitrary content into tabs with <htmlpress-tabs>, one <htmlpress-tab title> per tab.

Add a sync attribute to synchronize tab selection across tab groups. When a reader selects a tab in one group, every other group with the same sync key switches to the matching tab, and the choice is remembered across pages in localStorage.

<htmlpress-tabs sync="channel">
  <htmlpress-tab title="cargo"><p>From crates.io, built on your machine.</p></htmlpress-tab>
  <htmlpress-tab title="npm"><p>A prebuilt binary per platform.</p></htmlpress-tab>
  <htmlpress-tab title="pip"><p>A binary wheel.</p></htmlpress-tab>
</htmlpress-tabs>
:::tab{title="cargo" sync="channel"}
From crates.io, built on your machine.
:::

:::tab{title="npm"}
A prebuilt binary per platform.
:::

:::tab{title="pip"}
A binary wheel.
:::

Renders as (both groups share sync="channel"; switch one):

cargo install htmlpress
npm install -g gethtmlpress
pip install htmlpress

From crates.io, built on your machine.

A prebuilt binary per platform.

A binary wheel.

Steps

A heading with data-step is a numbered step, the steps counting up through the page; its content follows it as usual. Those headings stay out of the page's table of contents.

<h3 data-step>Install</h3>
<p>…</p>
<h3 data-step>Write a page</h3>
<p>…</p>
### Install [step]

…

### Write a page [step]

…

Renders as:

Install

Pick a channel from the tabs above.

Write a page

Any .html file in the folder.

Start

Run htmlpress start and open the URL it prints.

Cards

Cards in <htmlpress-cards> fill two columns, one on narrow screens. A card's title is its heading, an href makes the whole card clickable, an icon shows before the title in the accent colour, and its content is the card's body.

<htmlpress-cards>
  <htmlpress-card title="Getting Started" href="/introduction/" icon="rocket">
    <p>Learn how to set up your first project.</p>
  </htmlpress-card>
  <htmlpress-card title="Plain HTML"><p>…</p></htmlpress-card>
</htmlpress-cards>
:::card{title="Getting Started" href="/introduction/" icon="rocket"}
Learn how to set up your first project.
:::

:::card{title="Plain HTML"}
…
:::

Renders as:

Getting Started

Learn how to set up your first project.

Configuration

Configure your htmlpress project.

GitHub

View the source code on GitHub.

Plain HTML

A card without a link is not clickable.

Headings inside a card stay out of the page's table of contents.

Badges

An inline label. variant is secondary or outline for a plainer style, or positive, warning or destructive for a tone; without it, solid in the accent.

<htmlpress-badge>New</htmlpress-badge>
<htmlpress-badge variant="positive">Stable</htmlpress-badge>
:badge[New] :badge[Stable]{variant="positive"}

Renders as: New Secondary Stable Beta Removed Outline

Buttons

<htmlpress-button href label> is a call to action linking to its href. variant is secondary, outline, ghost or link for a quieter one, and positive, warning or destructive for a toned one; size is sm or lg.

<htmlpress-button href="/introduction/" label="Get Started"></htmlpress-button>
<htmlpress-button href="…" label="GitHub" variant="secondary"></htmlpress-button>
::button[Get Started]{href="/introduction/"}

::button[GitHub]{href="…" variant="secondary"}

Renders as:

Get Started GitHub Outline Link

Icons

<htmlpress-icon name="…"> draws a built-in Lucide icon inline, in the text's color and size; the same names go in the icon of a link or a section. An unknown name fails the build. These are the 114 built in:

<htmlpress-icon name="rocket"></htmlpress-icon> Get started
:icon{name="rocket"} Get started

activity

archive

arrow-right

badge-check

bell

blocks

book

book-marked

book-open

book-text

bookmark

bot

box

braces

brain

bug

calendar

chart-column

check

circle-help

clock

cloud

cloud-upload

code

codepen

coffee

compass

cpu

database

download

external-link

feather

figma

file

file-code

file-pen-line

file-text

flag

flask-conical

folder

git-branch

git-commit-horizontal

git-pull-request

github

gitlab

globe

graduation-cap

hammer

heading

heart

heart-handshake

history

house

image

info

key

layers

layout-grid

layout-panel-left

library

life-buoy

lightbulb

link

linkedin

list

lock

mail

map

megaphone

message-circle

monitor

newspaper

notebook-pen

package

palette

pencil

pencil-ruler

play

plug

presentation

puzzle

rocket

route

rss

scale

scroll

search

server

settings

shield

sliders-horizontal

smartphone

sparkles

square-dashed

square-stack

star

table

tag

terminal

triangle

trophy

twitter

type

upload

user

users

video

webhook

wind

workflow

wrench

x

youtube

zap

File Tree

A nested list inside <htmlpress-filetree>; an item holding a list is a folder.

<htmlpress-filetree>
  <ul>
    <li>docs<ul><li>index.html</li></ul></li>
    <li>htmlpress.yaml</li>
  </ul>
</htmlpress-filetree>
:::filetree
- docs
  - index.html
- htmlpress.yaml
:::

Renders as:

  • docs
    • index.html
    • guides
      • build.html
  • htmlpress.yaml

Columns

<htmlpress-columns> lays out its children side by side, two by default and up to four with cols, each <htmlpress-column> one column:

<htmlpress-columns cols="2">
  <htmlpress-column><p><strong>Left column</strong> with content.</p></htmlpress-column>
  <htmlpress-column><p><strong>Right column</strong> with more content.</p></htmlpress-column>
</htmlpress-columns>
:::column
**Left column** with content.
:::

:::column
**Right column** with more content.
:::

Renders as:

Left column with content, including lists:

  • Item one
  • Item two

Right column with more content:

A blockquote works here too.

Theme tokens

Colors, fonts and widths are CSS custom properties on :root, with a dark set under prefers-color-scheme or the header's theme toggle: --htmlpress-accent, --htmlpress-accent-text, --htmlpress-banner, --htmlpress-banner-text, --htmlpress-highlight, --htmlpress-highlight-text, --htmlpress-prose, --htmlpress-prose-strong, --htmlpress-prose-marker, --htmlpress-bg, --htmlpress-surface, --htmlpress-text, --htmlpress-muted, --htmlpress-border, --htmlpress-info, --htmlpress-success, --htmlpress-warning, --htmlpress-danger, --htmlpress-font, --htmlpress-mono, --htmlpress-radius, --htmlpress-shadow, --htmlpress-width and --htmlpress-nav-width. Override them from a page's own stylesheet:

:root {
  --htmlpress-accent: oklch(0.6 0.18 30);
  --htmlpress-font: "Inter", system-ui, sans-serif;
  --htmlpress-width: 52rem;
}

Layout

The layout is plain HTML. Htmlpress fills its <head> (charset, viewport, title, description, social preview tags, canonical link, favicon, the theme, the styles and scripts of the components the page uses, the head tags from htmlpress.yaml, then the page's own head tags) and replaces these elements at build time:

<htmlpress-content>
The page's content.
<htmlpress-brand>
The site title with the description below it, after the logo when set, linking home.
<htmlpress-banner>
The banner from htmlpress.yaml.
<htmlpress-breadcrumbs>
Home, every folder above the page (named and linked by its index page when it has one), then the page.
<htmlpress-nav>
The open section's pages (every page without sections), grouped by top folder under an "Articles" label ("Posts" in a blog, "Releases" in a changelog); a folder's group is named by its index page and links to it. The sidebar sections open it and the sidebar links close it, under "Links".
<htmlpress-links>
The header sections, the open one marked, then the header links from htmlpress.yaml.
<htmlpress-page-toc>
The page's <h2> and <h3>, highlighting the one in view. A heading without an id gets one from its text.
<htmlpress-pager>
The previous and next pages in navigation order.
<htmlpress-edit>
An "Edit on GitHub" link from edit in htmlpress.yaml, on its own; the default layout has it inside <htmlpress-toolbar>.
<htmlpress-search>
Search over every page, with the script: a header button, also opened by S, / or ⌘K / Ctrl K. The build writes the index to _htmlpress/search.json, split at each page's headings, and the dialog loads it on first open. Any word of the query matches, as a word's start or within one typo; a result opens its page with ?highlight= the query, whose matches are painted in --htmlpress-highlight and scrolled to. Below 56rem the field takes over the header instead of a dialog.
<htmlpress-toolbar>
The page's actions under an "Actions" title: the source link, then a link to the page's Markdown copy, which the script swaps for "Copy Markdown", "Open in ChatGPT" and "Open in Claude".
<htmlpress-footer>
A "Created with Htmlpress" credit.
<htmlpress-language>
The language picker, linking to this page in each language, dropped down or, on a phone, in a sheet; only on a site with translations.
<htmlpress-shortcuts>
A header menu of the keyboard shortcuts, with the script, listing every key and disabling the ones the page does not answer to, such as L without a next page; a row also presses its key. Hidden below 56rem, where there is no keyboard.
<htmlpress-skip>
The "Skip to content" link, shown only on focus.

Every string these elements and their scripts show comes in the page's language. The scripts read theirs from a <script type="application/json" id="htmlpress-messages"> htmlpress writes into the head, and fall back to English without it.

An element with nothing to show is removed. <htmlpress-nav-toggle> (the sidebar as a drawer on a phone; wider, it folds the sidebar away and remembers that), <htmlpress-toc-bar> (narrower than the table of contents' column, a bar under the header naming the heading in view, which opens a sheet of the page's contents and actions), <htmlpress-theme-toggle> (a menu of light, dark and the system's choice, dropped down or, on a phone, in a sheet) and <htmlpress-back-to-top> are built by the script in the browser. Their keys match Livemark's: M toggles the sidebar, T flips light and dark and U goes back to the top, while J and K scroll any page down and up and D goes to its bottom. With a <htmlpress-pager> on the page, L and H go to the next and previous page. None fires while typing in a field.

Every phone sheet, the contents, the theme, the language and the sidebar's section picker, is one <htmlpress-sheet> the scripts add to the body. It closes on a swipe down, a tap on the backdrop, Esc or its close button, so escaping components/sheet/sheet.css restyles all of them.

The frame around them is made of elements too. They hold no content of their own, only style and place what is inside them, so a layout keeps the ones it wants and gives them landmark roles as attributes:

<htmlpress-shell>
The sidebar beside the rest; stacked on a phone.
<htmlpress-sidebar>
The brand and the navigation; a drawer on a phone.
<htmlpress-main>
The column beside the sidebar.
<htmlpress-header>
The sticky bar on top, showing its brand and menu button only on a phone.
<htmlpress-page>
The <main> it holds beside the aside.
<htmlpress-aside>
The column beside the content, hidden when empty or narrow.

A .htmlpress/layout.html in the project replaces the built-in layout, and a page can pick its own from .htmlpress/layouts/. Every component's styles and script can be replaced or added the same way: see Overriding and Escaping.

Created with ❤ and Htmlpress

Actions

Edit on GitHubView as Markdown

Contents