caliper uidocs

Legal template

Block

A policy people can read: the short version first, numbered sections with an outline that follows you, linkable clauses, a change history and a print layout.

Installs components/ui/legal-template.tsxDepends on @radix-ui/react-slot, lucide-reactMotion none in component source
pnpm dlx shadcn@latest add https://caliperui.site/r/legal-template.json
Skip to content

Legal

Privacy policy

What we collect when you use Halden, why, who we share it with and the choices you have.

Last updated

In effect from

  • We collect what we need to run your close: your account, your team and the financial data you connect.
  • We never sell personal data or use your financial data to train models.
  • Data is stored in the EU (Frankfurt) and you can export or delete it at any time.
  • You can ask us what we hold about you, and we will answer within 30 days.

This summary helps you read the policy; the numbered sections below are what applies.

1.What we collect

Account details you give us: your name, work email and role. Usage details from the app: which pages are opened and when, so we can fix what is slow.

Financial data you connect, such as bank transactions and ledger entries, is processed only to provide the service.

2.How we use it

To provide and support Halden, to bill you, to keep the service secure and, with your permission, to send product news. We do not use your financial data for advertising or to train machine learning models.

3.Who we share it with

Processors that help us run the service, under contract: our cloud host (AWS, Frankfurt), our email provider and our payment processor. The current list is in our subprocessor register.

4.How long we keep it

While your account is open, and for 30 days after you close it, then it is deleted from live systems. Backups roll off within a further 35 days. Invoices are kept for ten years because tax law requires it.

5.Your rights

You can access, correct, export or delete your personal data, object to processing and complain to your data protection authority. Write to the address below and we will answer within 30 days.

6.Changes to this policy

We will email account owners at least 14 days before a change that affects how we use personal data.

  1. Added our new email provider and clarified backup retention.
  2. Moved data storage from Ireland to Frankfurt. Read that version
  3. First version. Read that version

Questions about this policy? Write to privacy@halden.app.

When to use #

Use it for

  • Privacy policy, terms of service, a data processing addendum.
  • Any long document people need to cite by section.

Skip it when

  • Marketing copy; legal pages should read as plain and stable.

Installation #

terminal
pnpm dlx shadcn@latest add https://caliperui.site/r/legal-template.json

Adds its 8 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.

Usage #

This is the code behind the preview above.

example.tsx
import { LegalTemplate } from "@/components/ui/legal-template"

const pages = ["blog-post-template", "about-template", "contact-template", "legal-template", "error-template", "profile-page"];

const nav = (current: string) =>
  [
    { label: "Product", href: "#product" },
    { label: "Customers", href: "#customers" },
    { label: "Blog", href: "#blog" },
    { label: "About", href: "#about" },
    { label: "Contact", href: "#contact" },
  ].map((link) => ({ ...link, current: link.label.toLowerCase() === current }));

const signIn = { label: "Sign in", href: "#" };

const frame = "h-[720px] w-full overflow-auto rounded-[14px] shadow-[0_0_0_1px_var(--border)]";

export function LegalDemo() {
  return (
    <div className={frame}>
      <LegalTemplate
        brand="Halden"
        nav={nav("")}
        signIn={signIn}
        primary={heroes.primary!}
        title="Privacy policy"
        lead="What we collect when you use Halden, why, who we share it with and the choices you have."
        updated="2026-09-30"
        effective="2026-10-15"
        summary={[
          "We collect what we need to run your close: your account, your team and the financial data you connect.",
          "We never sell personal data or use your financial data to train models.",
          "Data is stored in the EU (Frankfurt) and you can export or delete it at any time.",
          "You can ask us what we hold about you, and we will answer within 30 days.",
        ]}
        sections={[
          { id: "collect", title: "What we collect", body: <><p>Account details you give us: your name, work email and role. Usage details from the app: which pages are opened and when, so we can fix what is slow.</p><p>Financial data you connect, such as bank transactions and ledger entries, is processed only to provide the service.</p></> },
          { id: "use", title: "How we use it", body: <p>To provide and support Halden, to bill you, to keep the service secure and, with your permission, to send product news. We do not use your financial data for advertising or to train machine learning models.</p> },
          { id: "share", title: "Who we share it with", body: <><p>Processors that help us run the service, under contract: our cloud host (AWS, Frankfurt), our email provider and our payment processor. The current list is in our <a href="#subprocessors">subprocessor register</a>.</p></> },
          { id: "keep", title: "How long we keep it", body: <p>While your account is open, and for 30 days after you close it, then it is deleted from live systems. Backups roll off within a further 35 days. Invoices are kept for ten years because tax law requires it.</p> },
          { id: "rights", title: "Your rights", body: <p>You can access, correct, export or delete your personal data, object to processing and complain to your data protection authority. Write to the address below and we will answer within 30 days.</p> },
          { id: "changes", title: "Changes to this policy", body: <p>We will email account owners at least 14 days before a change that affects how we use personal data.</p> },
        ]}
        versions={[
          { date: "2026-09-30", summary: "Added our new email provider and clarified backup retention." },
          { date: "2026-03-12", summary: "Moved data storage from Ireland to Frankfurt.", href: "#v2" },
          { date: "2025-06-01", summary: "First version.", href: "#v1" },
        ]}
        contact={{ label: "privacy@halden.app", href: "mailto:privacy@halden.app" }}
        footer={footers}
      />
    </div>
  );
}

API reference #

LegalTemplate

component
PropTypeDefaultDescription
brand *string—
navreadonly BlockNavLink[]—
signInBlockAction—
primaryBlockAction—
eyebrowstring"Legal"
title *string—
leadstring—
updated *string—ISO date of the last change.
effectivestring—ISO date the current text applies from, if different.
summaryreadonly string[][]The short version, in plain sentences.
sections *readonly LegalSection[]—
versionsreadonly LegalVersion[][]Earlier versions, newest first.
contact{ label: string; href: string; }—Who answers questions, e.g. { label: "privacy@halden.app", href: "mailto:privacy@halden.app" }.
footerTemplateFooter—
classNamestring—

Accessibility #

It is built on native elements and keeps aria-hidden, aria-labelledby and aria-label in step with state.

No custom key handling; Tab and the native activation keys do the work.

Motion #

It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.