- Components
Scroll area
Content that scrolls inside a fixed box: a named region, a tab stop, a thin scrollbar and a soft edge where there is more.
npx shadcn add @klarhimmel/scroll-areaWhen to use
Use for
A list in a card, a code block or a strip that must not push the page.
Not for
Tables. Table scrolls itself. A whole page. Let the page scroll.
Pairs with
Card, Popover, code.
Preview
scroll-area.tsx
import { Theme } from '@/components/klarhimmel/theme/style';
import { ScrollArea } from '@/components/klarhimmel/ui/scroll-area';
export default function Example() {
return (
<Theme theme="brand">
<ScrollArea aria-label="Rooms and rates" className="max-h-64">
<ul>
<li>Room 201, Garden, 1 190 kr</li>
<li>Room 202, Seaside, 1 340 kr</li>
<li>Room 203, Loft, 1 490 kr</li>
</ul>
</ScrollArea>
</Theme>
);
}Install
Import
import { ScrollArea } from '@/components/klarhimmel/ui/scroll-area';- Lands in
- components/klarhimmel/ui/scroll-area.tsx, plus cn() and the theme item if they are missing. Import theme.css after Tailwind.
- Render in
- Render it inside <Theme>, once near the root of your app. Tokens and fonts are scoped to it, so outside it the component is unstyled.
Examples
Horizontal
import { ScrollArea } from '@/components/klarhimmel/ui/scroll-area'; const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun', 'Mon', 'Tue', 'Wed']; export default function ScrollAreaHorizontal() { return ( <div className="w-[min(28rem,calc(100cqw-3rem))]"> <ScrollArea aria-label="Next ten days" orientation="horizontal" className="pb-3"> <ul className="flex gap-3"> {days.map((d, i) => ( <li key={i} className="flex h-24 w-28 shrink-0 flex-col justify-between rounded-kh-lg border border-kh-line bg-kh-surface p-3 text-kh-small"> <span className="font-medium">{d} {16 + i} Nov</span> <span className="text-kh-muted">{i % 3 === 0 ? 'Full' : `${4 + (i % 4)} rooms free`}</span> </li> ))} </ul> </ScrollArea> </div> ); }Code
import { ScrollArea } from '@/components/klarhimmel/ui/scroll-area'; const code = `{ "booking": "4821", "room": "204", "guests": [ { "name": "Maja Sund", "arrival": "2026-11-14", "nights": 2, "note": "Late check-in, travel cot needed, quiet room away from the lift" }, { "name": "Oskar Lind", "arrival": "2026-11-14", "nights": 2, "note": "Allergic to feathers: synthetic bedding" } ], "rate": { "code": "REFUNDABLE", "total": 2380, "currency": "SEK", "refundable_until": "2026-11-07" } }`; export default function ScrollAreaCode() { return ( <div className="w-[min(28rem,calc(100cqw-3rem))] rounded-kh-lg bg-kh-surface-2 p-2"> <ScrollArea aria-label="Booking payload" orientation="both" className="max-h-48"> <pre className="px-2 py-2 font-kh-mono text-kh-caption leading-relaxed text-kh-ink">{code}</pre> </ScrollArea> </div> ); }
API reference
| Prop | Type | Default | Description |
|---|---|---|---|
aria-label | string | - | Required: names the region, which keyboard users reach with Tab. |
orientation | 'vertical' | 'horizontal' | 'both' | 'vertical' | Which way it scrolls. Set the height or width with a class such as max-h-64. |
className | string | - | Extra classes, merged after the component's own. |
Accessibility
| Key | Does |
|---|---|
Tab | Reaches the region |
Arrow keys | Scroll by a line |
Page Up / Page Down / Space | Scroll by a page |
Home / End | Jump to the start or the end |
The region is named and focusable, so a keyboard can scroll it. The scrollbar is thin but always drawn where the platform allows, and a soft edge shows where there is more.
Accessibility