layout
Scroll area
A scrollable region with custom scrollbars, rendered by the included behavior script.
UpdatedCSS onlyPlain classes; no JavaScript in any stack.
Usage
Load dist/ca-scroll-area.js; it renders a scrollbar per overflowing axis and keeps the thumb, the data-* state and the fade variables in sync while the viewport scrolls natively.
<!-- The viewport scrolls natively; dist/ca-scroll-area.js renders the
scrollbar parts and keeps them in sync. -->
<div class="ca-scroll-area h-48 w-full max-w-sm">
<div class="ca-scroll-area__viewport" tabindex="0">
<div class="ca-scroll-area__content">
<ul class="ca-stack">
<li>Intake — Monday 09:00</li>
<li>Theory lesson — Monday 11:00</li>
<li>Driving lesson — Tuesday 14:00</li>
<li>Driving lesson — Wednesday 09:30</li>
<li>Theory exam prep — Thursday 10:00</li>
<li>Driving lesson — Thursday 15:30</li>
<li>Mock exam — Friday 13:00</li>
<li>Driving lesson — Friday 16:00</li>
<li>Intake — Saturday 10:00</li>
<li>Theory lesson — Saturday 13:00</li>
</ul>
</div>
</div>
</div>Examples
Fade and gutter
--fade masks edges that still hide content; --gutter reserves room so content does not slide under the scrollbar.
<div class="flex w-full max-w-lg flex-wrap items-start gap-4">
<div class="ca-scroll-area ca-scroll-area--fade h-48 min-w-56 flex-1">
<div class="ca-scroll-area__viewport" tabindex="0">
<div class="ca-scroll-area__content">
<ul class="ca-stack">
<li>Intake — Monday 09:00</li>
<li>Theory lesson — Monday 11:00</li>
<li>Driving lesson — Tuesday 14:00</li>
<li>Driving lesson — Wednesday 09:30</li>
<li>Theory exam prep — Thursday 10:00</li>
<li>Driving lesson — Thursday 15:30</li>
<li>Mock exam — Friday 13:00</li>
</ul>
</div>
</div>
</div>
<div class="ca-scroll-area ca-scroll-area--gutter h-48 min-w-56 flex-1">
<div class="ca-scroll-area__viewport" tabindex="0">
<div class="ca-scroll-area__content">
<ul class="ca-stack">
<li>Intake — Monday 09:00</li>
<li>Theory lesson — Monday 11:00</li>
<li>Driving lesson — Tuesday 14:00</li>
<li>Driving lesson — Wednesday 09:30</li>
<li>Theory exam prep — Thursday 10:00</li>
<li>Driving lesson — Thursday 15:30</li>
<li>Mock exam — Friday 13:00</li>
</ul>
</div>
</div>
</div>
</div>Guidance and accessibility
When to use
- Use a scroll area where a visible native scrollbar disturbs the layout: long pick lists, side panels, code or log viewers.
- The markup stays plain, a
__viewportaround__content. The viewport scrolls natively (wheel, touch and arrow keys) and the core hides the native bar;dist/ca-scroll-area.jsrenders the__scrollbar,__thumband__cornerparts. It is Calaca’s own framework-free implementation, so no external library is needed. - The script owns placement and the
data-*state (data-orientation,data-hovering,data-scrolling,data-has-overflow-*) plus the--scroll-area-overflow-*variables--fadereads; the contract owns the look and the interaction states. - Without the script the parts simply stay absent: the region still scrolls, but shows no custom scrollbar.
Accessibility
- The viewport is focusable (
tabindex="0") so keyboard users can scroll it with arrow keys. - Scrollbars stay real interactive parts: drag the thumb, or click the track to page.
- The fade-in honors reduced motion through the skin’s motion-safe utilities.
Classes
Generated from the component contract. Parts use __, modifiers use --.
| Class | Kind | Use it for |
|---|---|---|
ca-scroll-area | Component | The frame; clips the content and anchors the scrollbar parts. |
ca-scroll-area__viewport | Part | The scrolling box; takes keyboard focus for arrow-key scrolling. |
ca-scroll-area__content | Part | The content wrapper inside the viewport. |
ca-scroll-area__scrollbar | Part | A scrollbar on one axis, rendered by the script while that axis overflows; it fades in while hovering or scrolling. |
ca-scroll-area__thumb | Part | The draggable thumb inside a scrollbar. |
ca-scroll-area__corner | Part | The square where horizontal and vertical scrollbars meet. |
ca-scroll-area--fade | Variant | Masks edges that still have scrollable content; the script keeps --scroll-area-overflow-* updated. |
ca-scroll-area--gutter | Variant | Reserves room for the scrollbar so content does not sit underneath it. |
Skins
The same markup, dressed by each skin. Structure and behavior stay the same; only the look changes.
Base skin
Neutral grayscale starting point; product skins extend it and change what differs.
Calaca skin
The Calaca UI brand: hueso paper and tinta ink, cempasúchil marigold, rosa and jade.
Bloque skin
Example skin pushed far from base: square, heavy, offset shadows, larger targets.
Pliego skin
Example skin from the press sheet: cool ground, bond-paper sheets, rule-grey hairlines, one red mark.
Framework notes
Link the prebuilt stylesheet of your skin next to your brand stylesheet. No build step.
<link rel="stylesheet" href="brand.css" />
<link rel="stylesheet" href="ca-base.css" />In Astro, Vite and other Tailwind projects, import Calaca after Tailwind and your brand in your main stylesheet.
@import "tailwindcss";
@import "./brand.css";
@import "@usecalaca/ui/core.css";
@import "@usecalaca/ui/skins/base.css";Same stylesheet as above; write the classes in className.
<button className="ca-button ca-button--primary ca-button--md" type="button">Save changes</button>