HTML Templating

Sapling provides two main methods for rendering HTML content: html and raw. These are convenient wrappers around the html and raw methods from Hono.

The html Template Literal

The html template literal allows you to write HTML with dynamic content interpolation:

import { html } from "@sapling/sapling";

function Greeting({ name }: { name: string }) {
  return html`
    <div class="greeting">
      <h1>Hello, ${name}!</h1>
    </div>
  `;
}

Safety Features

The html template automatically escapes interpolated values to prevent XSS attacks:

const userInput = '<script>alert("XSS")</script>';
html`<div>${userInput}</div>`; // Safely escaped

Nested Components

You can nest components and interpolate their results:

function Header() {
  return html`<header>Site Header</header>`;
}

function Page() {
  return html`
    <div>
      ${Header()}
      <main>Content</main>
    </div>
  `;
}

The raw Method

The raw method is used when you need to insert pre-rendered HTML content without escaping:

import { html, raw } from "@sapling/sapling";

function Article({ content }: { content: string }) {
  return html`
    <article>
      ${raw(content)} <!-- Content is inserted as-is -->
    </article>
  `;
}

Use Cases for raw

  • Rendering markdown content
  • Inserting sanitized HTML from a CMS
  • Including pre-rendered component output
import { renderMarkdown } from "@sapling/markdown";

async function MarkdownContent({ markdown }: { markdown: string }) {
  const rendered = await renderMarkdown(markdown);
  return html`
    <div class="prose">
      ${raw(rendered)}
    </div>
  `;
}

Conditional Rendering

You can use standard JavaScript expressions within templates:

function ConditionalContent({ isLoggedIn }: { isLoggedIn: boolean }) {
  return html`
    <div>
      ${isLoggedIn 
        ? html`<button>Logout</button>`
        : html`<button>Login</button>`
      }
    </div>
  `;
}

List Rendering

Render arrays of content using map:

function ItemList({ items }: { items: string[] }) {
  return html`
    <ul>
      ${items.map(item => html`
        <li>${item}</li>
      `)}
    </ul>
  `;
}

Best Practices

  1. Use html by Default: Always use the html template literal unless you specifically need raw
  2. Sanitize Raw Content: When using raw, ensure the content is from a trusted source or properly sanitized
  3. Type Safety: Leverage TypeScript for component props
  4. Keep It Simple: Prefer small, focused components over complex templates
  5. Performance: Avoid unnecessary nesting of templates

Security Considerations

  • The html template literal automatically escapes content to prevent XSS
  • Only use raw with trusted content
  • Always sanitize user-generated content before rendering
  • Be cautious when rendering HTML from external sources