Prose
A Markdown renderer hands back bare tags: <h2>, <p>, <ul>, <blockquote> — with no classes to hook onto. prose() wraps that HTML and styles it.
It is the one deliberate exception in this library. Everywhere else, styling is scoped to su- classes precisely so it never touches markup you did not opt into; here there are no classes to target, so the rules match bare tags — but only inside the wrapper.
Basic prose
Getting started
Write a function that returns HTML. Run sitelo build. Publish dist/.
- File-based routing
- Build-time data
- No client runtime
prose(
'<h2>Getting started</h2>' +
'<p>Write a function that returns HTML. Run <code>sitelo build</code>. Publish <code>dist/</code>.</p>' +
'<ul><li>File-based routing</li><li>Build-time data</li><li>No client runtime</li></ul>'
)Everything it styles
A heading
Body copy with a link, bold, and inline code.
A pull quote, set apart from the text around it.
- First
- Second
- Nested
export default () => "<h1>Hi</h1>"| Option | Default |
|---|---|
| cleanUrls | true |
| outDir | dist |
Press ⌘ K to search.
prose(
'<h3>A heading</h3>' +
'<p>Body copy with <a href="/docs">a link</a>, <strong>bold</strong>, and <code>inline code</code>.</p>' +
'<blockquote><p>A pull quote, set apart from the text around it.</p></blockquote>' +
'<ol><li>First</li><li>Second<ul><li>Nested</li></ul></li></ol>' +
'<pre><code>export default () => "<h1>Hi</h1>"</code></pre>' +
'<table><thead><tr><th>Option</th><th>Default</th></tr></thead>' +
'<tbody><tr><td>cleanUrls</td><td>true</td></tr><tr><td>outDir</td><td>dist</td></tr></tbody></table>' +
'<hr>' +
'<p>Press <kbd>⌘</kbd> <kbd>K</kbd> to search.</p>'
)Sizes
Small — for a card summary or a sidebar.
Medium — the default, for article body copy.
Large — for a short, prominent introduction.
stack({ gap: 'lg' },
prose({ size: 'sm' }, '<p><strong>Small</strong> — for a card summary or a sidebar.</p>'),
prose('<p><strong>Medium</strong> — the default, for article body copy.</p>'),
prose({ size: 'lg' }, '<p><strong>Large</strong> — for a short, prominent introduction.</p>'),
)With a Markdown blog
The shape the blog example wants: render the Markdown at build time, wrap the result, and ship it.
import { marked } from 'marked'
import { article, body, h1, html, head, title } from 'javascript-to-html'
import { container, prose, styles, text } from 'sitelo/ui'
export async function data({ params }) {
return { post: await loadPost(params.slug) }
}
export default ({ data }) => html({ lang: 'en' },
head(title(data.post.title), styles()),
body(
container({ size: 'sm' },
h1(data.post.title),
text({ variant: 'caption' }, data.post.date),
// marked returns a string of HTML with no classes on it
prose(marked.parse(data.post.markdown)),
),
),
)Components inside prose
Every prose rule excludes elements carrying an su- class, so a component dropped into a block of prose keeps its own styling instead of picking up article margins.
Some rendered Markdown, and then a component:
And back to prose.
prose(
'<p>Some rendered Markdown, and then a component:</p>',
alert({ color: 'warning', title: 'Still a normal alert' },
'It is not restyled by the prose block around it.'),
'<p>And back to prose.</p>',
)A word about trust
prose() renders its children as HTML — that is the whole point, and it is how javascript-to-html works throughout. If the HTML comes from somewhere you do not control, sanitize it before it gets here. A Markdown renderer with raw HTML disabled is usually enough.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
size | 'sm' | 'md' | 'lg' | 'md' | Base font size; everything else scales in em from it. |
as | string | 'div' | Element to render, e.g. article. |