Writing & markdown
Backroad has three primitives for emitting text into the page:
br.write, br.title, and br.link / br.linkGroup.
br.write — markdown
The workhorse. Pass any markdown string and Backroad renders it with GitHub-flavored markdown (headings, bold, lists, code fences, tables, blockquotes, inline HTML).
br.write({
body: `
# Hello
This is **bold**, *italic*, and \`inline code\`.
- one
- two
- three
\`\`\`ts
const greeting = 'hi';
\`\`\`
`,
});
body can also be a number, in which case it renders as a plain string.
Streaming markdown
br.write appends a new block on every call. To grow a single block over
time — streamed LLM output, a live log, incremental progress — use
writeStream or streamable, which create one markdown node and re-render it
in place rather than emitting new siblings:
// Pump an async iterable of text chunks; returns the full string when done.
const full = await br.writeStream(tokenStream);
// Or drive it by hand:
const { update } = br.streamable();
update('Working…');
update('Working… done ✅');
Most commonly used for chat — see LLM components.
br.title — quick page heading
A shortcut for br.write({ body: '# ...' }) that's slightly less noisy
when you just want a top-of-page title:
br.title({ label: 'Dashboard' });
br.link and br.linkGroup
For one link:
br.link({ label: 'Docs', href: '/docs', target: '_blank' });
For a nav-style row:
br.linkGroup({
items: [
{ label: 'Home', href: '/' },
{ label: 'Docs', href: '/docs' },
{
label: 'GitHub',
href: 'https://github.com/sudomakes/backroad',
target: '_blank',
},
],
});
Building markdown from values
Because body is just a string, you can interpolate any state from
earlier in the script:
const name = br.textInput({ label: 'Name', defaultValue: 'world' });
br.write({ body: `Hello, **${name}**!` });