Pricing, packages
Install
npx shadcn add @klarhimmel/pricing-packagesUsage
import { Theme } from '@/components/klarhimmel/theme/style';
import { BlockSurface } from '@/components/klarhimmel/blocks/surface';
import PricingPackages from '@/components/klarhimmel/blocks/pricing-packages';
export default function Section() {
return (
<Theme theme="brand">
<BlockSurface>
<PricingPackages props={{
"eyebrow": "What we build",
"title": "Working software in days, not months",
"description": "Five things that are built again and again. Yours may be none of them: tell us the job.",
"label": "Examples",
"packages": [
{
"name": "Booking sync",
"summary": "Your booking system and your calendar agree, without anyone retyping.",
"duration": "4 days",
"priceState": "shown",
"pricePrefix": "from",
"price": "24 000 kr",
"badge": "Start here",
"cta": {
"label": "Ask about this",
"href": "#review"
}
},
{
"name": "Guest assistant",
"summary": "Answers the questions guests ask every day, and hands over the rest.",
"duration": "1 week",
"priceState": "ask",
"price": "",
"cta": {
"label": "Ask about this",
"href": "#review"
}
},
{
"name": "Lead inbox",
"summary": "Every enquiry in one place, sorted and answered the same day.",
"duration": "5 days",
"priceState": "ask",
"price": "",
"cta": {
"label": "Ask about this",
"href": "#review"
}
},
{
"name": "Reporting pack",
"summary": "One page each Monday with the numbers you check by hand now.",
"duration": "3 days",
"priceState": "shown",
"pricePrefix": "from",
"price": "15 000 kr",
"cta": {
"label": "Ask about this",
"href": "#review"
}
}
],
"askLabel": "Ask",
"durationLabel": "Takes",
"keep": {
"label": "Keep it running",
"text": "After it is live we monitor it, fix what breaks and make small changes every month."
}
}} />
</BlockSurface>
</Theme>
);
}Install
Import
import Block from '@/components/klarhimmel/blocks/pricing-packages';- pricing/packages
- About
- A grid of three to six packages: name, one line on what you get, how long it takes, a price or the word "Ask" (never a made-up number), an optional flag, a button each, a visible "Examples" tag and an optional monthly line underneath.
- Category
- Plans and prices: tiers, a single plan, a toggle or a comparison table.
Notes
When to use it
A grid of three to six fixed-scope packages, each with a duration, a price or the word Ask and its own button. Use `pricing-tiers` for subscription plans with feature lists.
Writing for it
- Set priceState to 'ask' for any package without a ruled price. The block then prints askLabel and ignores the price field, so no number is invented. - The duration (40 characters) is read after the durationLabel, so write 'Days, not months' or '2 weeks' to complete the phrase 'Takes ...'. - Use the optional keep line for a monthly offer, with a 40 character label and 200 characters of text. The label tag, such as 'Examples', says the grid is a sample.
Watch out for
A package named in 'ask' state still needs a price string in the data, but it is hidden from view and only kept for editors. The flag badge is capped at 24 characters and wraps in a narrow card, so keep it to one or two words.
Pairs well with
Usage
The block in a page, with its default content (long lists shortened). Every prop is in the table below.
import { Theme } from '@/components/klarhimmel/theme/style';
import { BlockSurface } from '@/components/klarhimmel/blocks/surface';
import PricingPackages from '@/components/klarhimmel/blocks/pricing-packages';
export default function Section() {
return (
<Theme theme="brand">
<BlockSurface>
<PricingPackages props={{
"eyebrow": "What we build",
"title": "Working software in days, not months",
"description": "Five things that are built again and again. Yours may be none of them: tell us the job.",
"label": "Examples",
"packages": [
{
"name": "Booking sync",
"summary": "Your booking system and your calendar agree, without anyone retyping.",
"duration": "4 days",
"priceState": "shown",
"pricePrefix": "from",
"price": "24 000 kr",
"badge": "Start here",
"cta": {
"label": "Ask about this",
"href": "#review"
}
},
{
"name": "Guest assistant",
"summary": "Answers the questions guests ask every day, and hands over the rest.",
"duration": "1 week",
"priceState": "ask",
"price": "",
"cta": {
"label": "Ask about this",
"href": "#review"
}
}
],
"askLabel": "Ask",
"durationLabel": "Takes",
"keep": {
"label": "Keep it running",
"text": "After it is live we monitor it, fix what breaks and make small changes every month."
}
}} />
</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.
| Prop | Type | Default | Description |
|---|---|---|---|
eyebrow | string | 'What we build' | Text, up to 60 characters. Optional; empty is not rendered. |
title | string | 'Working software in days, not months' | Text, up to 120 characters. |
description | string | 'Five things that are built again an…' | Text, up to 300 characters. Optional; empty is not rendered. |
label | string | 'Examples' | Text, up to 24 characters. Optional; empty is not rendered. |
packages | { name, summary, duration, priceState, pricePrefix, price, badge, cta }[] | 4 items | List of 3 to 6. Each item: name, summary, duration, priceState ('shown' | 'ask'), pricePrefix (optional), price, badge (optional), cta. |
askLabel | string | 'Ask' | Text, up to 24 characters. |
durationLabel | string | 'Takes' | Text, up to 20 characters. |
keep | { label, text } | {…} | Fields: label, text. Optional; empty is not rendered. |
headingLevel | '1' | '2' | - | One of '1', '2'. Optional; empty is not rendered. |