Liasse

Quickstart

Install Liasse, define a document, apply a theme and render it to a real .xlsx file.

Install

pnpm add @liasse/core @liasse/xlsx

@liasse/core is format-agnostic; @liasse/xlsx is the adapter that produces the workbook. Importing the adapter registers the xlsx renderer.

Render your first workbook

report.ts
import { defineDocument, heading, table, render } from "@liasse/core";
import "@liasse/xlsx"; // registers the xlsx renderer
import { writeFile } from "node:fs/promises";

const doc = defineDocument({
  meta: { title: "Q3 2026 Results" },
  blocks: [
    heading("Revenue by line", { level: 1 }),
    table({
      columns: [
        { key: "item", header: "Item" },
        { key: "q3", header: "Q3", format: "currency", align: "right" },
        { key: "delta", header: "Δ", format: "percent", align: "right" },
      ],
      rows: [
        { item: "Subscriptions", q3: 472900, delta: 0.131 },
        { item: "Licenses", q3: 61300, delta: 0.163 },
      ],
      summary: { q3: "sum" },
      conditional: { column: "delta", rule: "positiveNegative" },
      xlsx: { freezeHeader: true },
    }),
  ],
});

const bytes = await render(doc, { format: "xlsx" });
await writeFile("q3-2026.xlsx", bytes);

That produces a real, themed .xlsx: a styled header row, the currency column formatted as #,##0.00 €, a real =SUM formula in the total row, the delta column colored green/red, and a frozen header.

render() returns the workbook as bytes (Uint8Array / Node Buffer). The library never writes files itself — you decide what to do with the bytes (write to disk, stream as an HTTP response, upload, …).

Apply your brand

Pass a theme derived from defaultTheme:

import { defineTheme, render } from "@liasse/core";

const theme = defineTheme({
  palette: { primary: "#0B5FFF" },
  table: { headerFill: "#E8F0FF" },
});

await render(doc, { format: "xlsx", theme });

Components and the adapter only ever read theme tokens — never hard-coded colors — so a single theme restyles every render.

Serve it from an API

import { render } from "@liasse/core";
import "@liasse/xlsx";

export async function GET() {
  const bytes = await render(doc, { format: "xlsx" });
  return new Response(bytes, {
    headers: {
      "content-type":
        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
      "content-disposition": 'attachment; filename="report.xlsx"',
    },
  });
}

Next, learn the core concepts — the block model, the builder DSL and the theme.

On this page