Getting Started
Components
- 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
'use client';
import { useState } from 'react';
import { PageNavigation } from '@/ui/PageNavigation';
const items = [
{ id: 'accommodation', label: 'Accommodation', href: '#accommodation', icon: 'Home' as const },
{ id: 'transport', label: 'Transport', href: '#transport', icon: 'PlaneDefault' as const },
{ id: 'people', label: 'People', href: '#people', icon: 'PeopleSingle' as const },
{ id: 'activities', label: 'Activities', href: '#activities', icon: 'Multisports' as const },
];
export function PageNavigationDemo() {
const [active, setActive] = useState('accommodation');
return (
<nav
aria-label="Demo wrapper"
onClick={(e) => {
const anchor = (e.target as HTMLElement).closest('a');
if (anchor) {
e.preventDefault();
const id = anchor.getAttribute('href')?.replace('#', '');
if (id) setActive(id);
}
}}
>
<PageNavigation items={items} activeItem={active} />
</nav>
);
}
Installation
npx shadcn@latest add https://develop.trident-ui.pro.clubmed/r/page-navigation.json
Usage
import { PageNavigation } from '@/ui/PageNavigation';
const items = [
{ id: 'accommodation', label: 'Accommodation', href: '/accommodation', icon: 'Home' },
{ id: 'transport', label: 'Transport', href: '/transport', icon: 'PlaneDefault' },
{ id: 'activities', label: 'Activities', href: '/activities', icon: 'Multisports' },
];
export function Component() {
return <PageNavigation items={items} activeItem="accommodation" />;
}Responsive behaviour
| Viewport | Active item | Inactive items |
|---|---|---|
Mobile (< md) | Black pill + label | Icon only (if icon provided) |
Desktop (≥ md) | Black pill + label | Label only |
API Reference
PageNavigation
| Prop | Type | Default | Description |
|---|---|---|---|
items | PageNavigationItem[] | Required | Ordered list of navigation items. |
activeItem | string | Required | The id of the currently active item. Controls the black pill indicator position and which label/icon is shown on mobile. |
className | string | — | Additional CSS classes applied to the <nav> element. |
PageNavigationItem
| Field | Type | Default | Description |
|---|---|---|---|
id | string | Required | Unique identifier used to match against activeItem. |
label | string | Required | Human-readable label displayed in the tab. |
href | string | Required | URL the tab links to. Rendered as a native <a> element. |
icon | IconicNames | — | Optional trident-icons icon name shown on mobile for inactive tabs. When omitted, the item shows nothing on mobile while inactive. |
Notes
- Each item is a native
<a>link — no JavaScript navigation is required for basic usage. PassonClickto intercept navigation in a SPA context. - The active item is marked with
aria-current="page"for screen readers. - The black pill is absolutely positioned behind the link text using
z-index, ensuring the link remains fully interactive. - The pill uses
transition-all duration-300— for a sliding animation across tabs, integrate a shared animated indicator using CSS or a motion library such asmotion/react. - Icon names must be valid
IconicNamesfrom@clubmed/trident-icons. Common choices for navigation:Home,PlaneDefault,PeopleSingle,Multisports,CalendarDefault,Search. - The component extends
ComponentPropsWithoutRef<'nav'>so all standard HTMLnavattributes (id,style,data-*, etc.) are forwarded.