- Accordion
- Advanced Toast
- AlertMessage
- ArrowButton
- Arrows
- Avatar
- Backdrop
- Basic Toast
- Breadcrumb
- Button
- CardBackground
- Card
- Carousel
- Chapters
- ChatBody
- ChatButton
- ChatHeader
- ChatInput
- ChatMessageActions
- ChatMessageEditor
- ChatMessage
- ChatTypingIndicator
- ChatWindowCsatPrompt
- ChatWindowQuote
- ChatWindow
- CheckboxSelect
- Checkbox
- Checkboxes
- Chip
- ChoiceExpander
- Clickable
- ContentReview
- Countdown
- CriteriaDates
- CriteriaParticipants
- CriteriaTransports
- Date Field
- Datepicker
- Dropdown
- ElasticHeight
- ExpandableCard
- ExpandableText
- Filter
- FloatingLabelTextField
- Form Control
- Form Label
- Frame
- HamburgerIcon
- Heading
- Image
- JourneyCard
- LayerHeader
- Layer
- Link
- Loader
- Number Field
- PageNavigation
- Pagination
- Paragraph
- Password
- Phone Field
- Popin
- Portal
- ProductThumbnail
- Promises
- Prose
- Radio Group
- RadioSelect
- Radio
- Range
- Scrollbar
- Select
- SidebarLayout
- SliderFrame
- SparkleWrapper
- Spinner
- Switch
- Table
- Tabs
- Tag
- TextField
- Toggle
- Tooltip
- ValidationMessage
1 - All-inclusive experience
From sunrise yoga to late-night entertainment, every moment is included. Fine dining, premium beverages, world-class facilities — yours without a second thought.
2 - Sports & activities
Surf, dive, sail, climb — over 60 land and water sports await you. Our certified instructors guide guests of all levels, from first-timers to seasoned athletes.
3 - Kids clubs
Dedicated clubs for every age from 4 months to 17 years. Supervised activities, creative workshops, and adventure programmes tailored to each stage of childhood.
'use client';
import { Chapters } from '@/ui/Chapters/Chapters';
export function ChaptersDemo() {
return (
<Chapters
chapters={[
{
title: 'All-inclusive experience',
content: (
<div className="min-h-screen p-40">
<p className="text-body max-w-prose">
From sunrise yoga to late-night entertainment, every moment is included. Fine
dining, premium beverages, world-class facilities — yours without a second thought.
</p>
</div>
),
},
{
title: 'Sports & activities',
content: (
<div className="min-h-screen p-40">
<p className="text-body max-w-prose">
Surf, dive, sail, climb — over 60 land and water sports await you. Our certified
instructors guide guests of all levels, from first-timers to seasoned athletes.
</p>
</div>
),
},
{
title: 'Kids clubs',
content: (
<div className="min-h-screen p-40">
<p className="text-body max-w-prose">
Dedicated clubs for every age from 4 months to 17 years. Supervised activities,
creative workshops, and adventure programmes tailored to each stage of childhood.
</p>
</div>
),
},
]}
theme="coreRange"
className="w-full"
/>
);
}
Installation
npx shadcn@latest add https://develop.trident-ui.pro.clubmed/r/chapters.json
Usage
import { Chapters } from '@/ui/Chapters/Chapters';
export function Component() {
return (
<Chapters
chapters={[
{
title: 'All-inclusive experience',
content: <section className="min-h-screen p-40">…</section>,
},
{
title: 'Sports & activities',
content: <section className="min-h-screen p-40">…</section>,
},
]}
theme="coreRange"
/>
);
}Anatomy
Chapters is composed of three internal sub-components:
| Sub-component | Role |
|---|---|
ChaptersSummary | Sticky sidebar <nav> with one link per chapter; hidden on mobile |
Chapter | Wrapper <section> that observes its own intersection to report active state |
ChapterTitle | Sticky mobile heading that anchors each chapter section |
API Reference
Chapters
| Prop | Type | Default | Description |
|---|---|---|---|
chapters | ChapterItem[] | Required | Array of chapter objects; each has a title and arbitrary content |
theme | Theme | 'coreRange' | Visual theme — controls sidebar and title background/text colours |
hLevel | 2 | 3 | 4 | 2 | Heading level for each chapter title (<h2> by default) |
icon | IconicNames | undefined | Override the default brand icon shown at the bottom of the sidebar |
onClick | (chapter: ChapterItem) => void | undefined | Called when a chapter title or sidebar link is clicked |
className | string | undefined | Additional CSS classes on the root <section> |
ChapterItem
| Field | Type | Description |
|---|---|---|
title | string | Chapter heading text and sidebar label |
content | ReactNode | Arbitrary content rendered below the title |
Themes
The theme prop switches the sidebar and mobile title bar colours. Supported values:
| Value | Background | Text | Icon |
|---|---|---|---|
coreRange (default) | lightSand | black | Trident |
exclusiveCollection | ultramarine | white | ExclusiveCollection |
happyToCare | verdigris | black | HappyToCare |
sienna | sienna | white | Trident |
black | black | white | Trident |
white | white | black | Trident |
light | lightSand | black | Trident |
dark | ultramarine | white | ExclusiveCollection |
Behaviour
Scroll-driven active chapter
Each Chapter section registers an IntersectionObserver against its root element. The active
chapter index is determined by which section satisfies one of three visibility rules:
- Section height ≤ half the viewport and intersection height > one-third the viewport
- Section height ≤ half the viewport and section is fully visible
- Section height > half the viewport and intersection height > half the viewport
The matching chapter's sidebar link is displayed at full opacity; inactive links are shown at 50 %.
Mobile sticky titles
On mobile, each chapter title sticks to the top of the viewport as the user scrolls through that section, allowing orientation without an always-visible sidebar.
Anchor-based navigation
Sidebar links and the "next chapter" arrow anchor to #chapter{index}, enabling in-page keyboard
navigation and shareable deep links.
Accessibility
- The sidebar is a
<nav>landmark; screen readers announce it as navigation. - Each chapter is a
<section>element — equivalent to aregionlandmark when given an accessible name via itsid. - Chapter titles are rendered as
<h2>(configurable viahLevel), providing document outline structure for assistive technology. - The "next chapter" arrow on mobile is an
<a>element targeting the subsequent chapter anchor. - The sidebar brand icon is purely decorative (no accessible name required).
Notes
- All four files (
Chapters,Chapter,ChapterTitle,ChaptersSummary) are marked'use client'— they depend onuseState,useEffect, and browser APIs. IntersectionObserveris used directly; it is not available in JSDOM. Tests must provide a stub — see the spec file for the pattern.- The sidebar is hidden on mobile (
hidden md:block) and shown atmdbreakpoint and above. On mobile,ChapterTitleprovides equivalent navigation via sticky headings and prev/next anchors. - The optional
iconprop accepts anyIconicNamesvalue from@clubmed/trident-icons. When omitted, the theme's default icon is used (usuallyTrident, or the brand-specific icon).