Klarhimmel UI

Report, decisions

Report, decisions preview

Install

npx shadcn add @klarhimmel/report-decisions

Usage

import { Theme } from '@/components/klarhimmel/theme/style';
import { BlockSurface } from '@/components/klarhimmel/blocks/surface';
import ReportDecisions from '@/components/klarhimmel/blocks/report-decisions';

export default function Section() {
  return (
    <Theme theme="brand">
      <BlockSurface>
        <ReportDecisions props={{
          "title": "What needs your call",
          "lead": "Each one has a default. Say nothing and the default stands.",
          "items": [
            {
              "question": "Deploy the preview?",
              "recommended": "Yes: one command, behind your existing sign-in.",
              "options": [
                "Keep it local for now"
              ],
              "why": "The directory passes its public-safety rules. Only the preview address is missing.",
              "reply": "",
              "id": "D-20261010-sample-1",
              "version": "1",
              "seat": "library",
              "repo": "ui",
              "session": "",
              "askedAt": "2026-10-10T14:00:00Z"
            },
            {
              "question": "Show prices on the packages page?",
              "recommended": "No: ask for a price.",
              "options": [
                "Show a from-price",
                "Show full prices"
              ],
              "why": "Prices depend on scope; a number without it sets the wrong expectation.",
              "reply": "",
              "id": "D-20261010-sample-2",
              "version": "1",
              "seat": "library",
              "repo": "ui",
              "session": "",
              "askedAt": "2026-10-10T14:00:00Z"
            }
          ],
          "replyHint": "Reply with the numbers, for example \"yes to all except 2\"."
        }} />
      </BlockSurface>
    </Theme>
  );
}

Install

Import

import Block from '@/components/klarhimmel/blocks/report-decisions';
Also called
  • report/decisions
About
Numbered decisions for the reader. Each has a question, the recommended default, the other options and why, so the answer can be "yes to all except 2". With an id on a card, the reader can answer on the page (see the report kit).
Category
A document for a reader: key figures, decisions with a recommended default, long-cell tables, timelines, callouts, sources and prose. Rendered to one HTML file by kh-report.

Notes

When to use it

Numbered questions that need an answer from the reader, each with a recommended default so the reply can be "yes to all except 2". Use `report-callout` for a single heads-up that needs no reply, and `report-table` when you compare options without asking for a choice.

Writing for it

- Write each question so it can be answered alone. It holds 240 characters and renders as the card's heading, so the card has to make sense when quoted in a reply. - Put your own pick in recommended (400 characters), then list only the real alternatives in options, up to six. If an option repeats the recommended one, the form shows it once. - Use why (700 characters) for the cost of choosing wrong. Give a card an id, plus seat and session, only if it should be answerable on the page; the form then sends the reply with that address.

Watch out for

A card with an id turns into a form, and then the recommended text, the options list and the reply hint are shown as radio choices instead. A card without an id is read-only, and reply (60 characters) is shown only there.

Usage

The block in a page, with its default content (long lists shortened). Every prop is in the table below.

section.tsx
import { Theme } from '@/components/klarhimmel/theme/style';
import { BlockSurface } from '@/components/klarhimmel/blocks/surface';
import ReportDecisions from '@/components/klarhimmel/blocks/report-decisions';

export default function Section() {
  return (
    <Theme theme="brand">
      <BlockSurface>
        <ReportDecisions props={{
          "title": "What needs your call",
          "lead": "Each one has a default. Say nothing and the default stands.",
          "items": [
            {
              "question": "Deploy the preview?",
              "recommended": "Yes: one command, behind your existing sign-in.",
              "options": [
                "Keep it local for now"
              ],
              "why": "The directory passes its public-safety rules. Only the preview address is missing.",
              "reply": "",
              "id": "D-20261010-sample-1",
              "version": "1",
              "seat": "library",
              "repo": "ui",
              "session": "",
              "askedAt": "2026-10-10T14:00:00Z"
            },
            {
              "question": "Show prices on the packages page?",
              "recommended": "No: ask for a price.",
              "options": [
                "Show a from-price",
                "Show full prices"
              ],
              "why": "Prices depend on scope; a number without it sets the wrong expectation.",
              "reply": "",
              "id": "D-20261010-sample-2",
              "version": "1",
              "seat": "library",
              "repo": "ui",
              "session": "",
              "askedAt": "2026-10-10T14:00:00Z"
            }
          ],
          "replyHint": "Reply with the numbers, for example \"yes to all except 2\"."
        }} />
      </BlockSurface>
    </Theme>
  );
}

Props

The type, default and text limit of every prop. On a real page, over-limit text is kept and checkSections flags it (Installation, Check a page before you ship); this live preview shows the default until it fits. The panel above edits all props.

PropTypeDefaultDescription
titlestring'What needs your call'Text, up to 100 characters.
leadstring'Each one has a default. Say nothing…'Text, up to 400 characters.
items{ question, recommended, options, why, reply, id, version, seat, repo, session, 2 itemsList of 1 to 12. Each item: question, recommended, options, why, reply, id, version, seat, repo, session, askedAt.
replyHintstring'Reply with the numbers, for example…'Text, up to 200 characters.
headingLevel'1' | '2'-One of '1', '2'. Optional; empty is not rendered.