Mountain Resort
Winter Collection
'use client';
import { FrameLabelsWrapper } from '@/ui/frame/FrameLabelsWrapper';
import { FrameTitle } from '@/ui/frame/FrameTitle';
import { SliderFrame } from '@/ui/frame/SliderFrame';
export function SliderFrameDemo() {
return (
<SliderFrame
format="horizontal"
className="max-w-380"
items={Array.from({ length: 5 }, (_, i) => ({
alt: `Mountain landscape ${i + 1}`,
src: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4',
}))}
labels={{ next: 'Next image', previous: 'Previous image' }}
>
<FrameLabelsWrapper hasImage>
<FrameTitle className="w-full justify-center text-center" hasImage>
<div>
<div className="text-b2 font-semibold">Mountain Resort</div>
<div className="text-b3">Winter Collection</div>
</div>
</FrameTitle>
</FrameLabelsWrapper>
</SliderFrame>
);
}
SliderFrame extends FrameWrapper with a carousel of images. When multiple items are provided it renders an embla-powered carousel with previous/next buttons that appear on hover. When only one item is provided, it renders a static image without carousel overhead.
npx shadcn@latest add https://develop.trident-ui.pro.clubmed/r/slider-frame.json
import { FrameLabelsWrapper } from '@/ui/frame/FrameLabelsWrapper';
import { FrameTitle } from '@/ui/frame/FrameTitle';
import { SliderFrame } from '@/ui/frame/SliderFrame';
export function Component() {
return (
<SliderFrame
format="horizontal"
className="max-w-380"
items={[
{ alt: 'Image 1', src: '/images/photo-1.jpg' },
{ alt: 'Image 2', src: '/images/photo-2.jpg' },
{ alt: 'Image 3', src: '/images/photo-3.jpg' },
]}
labels={{ next: 'Next image', previous: 'Previous image' }}
>
<FrameLabelsWrapper hasImage>
<FrameTitle className="w-full justify-center text-center" hasImage>
<div className="text-b2 font-semibold">Mountain Resort</div>
</FrameTitle>
</FrameLabelsWrapper>
</SliderFrame>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
items | ImageProps[] | Required | Array of image props. A single item renders without carousel |
labels | { next: string; previous: string } | Required | Accessible labels for the previous/next navigation buttons |
describedby | string | undefined | aria-describedby id passed to the navigation buttons |
format | "horizontal" | "vertical" | "square" | "custom" | "horizontal" | Aspect ratio of the frame |
as | "article" | "div" | "span" | "article" | HTML element to render |
className | string | undefined | Additional CSS classes |
children | ReactNode | undefined | Overlay content (use FrameLabelsWrapper + FrameTitle) |
'use client';
import { Button } from '@/ui/buttons/Button';
import { FrameLabelsWrapper } from '@/ui/frame/FrameLabelsWrapper';
import { FrameTitle } from '@/ui/frame/FrameTitle';
import { SliderFrame } from '@/ui/frame/SliderFrame';
export function SliderFrameWithButtonDemo() {
return (
<SliderFrame
format="horizontal"
className="max-w-380"
items={Array.from({ length: 5 }, (_, i) => ({
alt: `Mountain landscape ${i + 1}`,
src: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4',
}))}
labels={{ next: 'Next image', previous: 'Previous image' }}
>
<FrameLabelsWrapper hasImage>
<FrameTitle className="w-full justify-between" hasImage>
<div>
<div className="text-b2 font-semibold">Mountain Resort</div>
<div className="text-b3">Winter</div>
</div>
<Button
aria-label="Explore Mountain Resort"
className="pointer-events-auto shrink-0"
color="white"
icon="ArrowDefaultRight"
theme="outline"
variant="circle"
/>
</FrameTitle>
</FrameLabelsWrapper>
</SliderFrame>
);
}
'use client';
import { Button } from '@/ui/buttons/Button';
import { Tag } from '@/ui/Tag';
import { FrameLabelsWrapper } from '@/ui/frame/FrameLabelsWrapper';
import { FrameTitle } from '@/ui/frame/FrameTitle';
import { SliderFrame } from '@/ui/frame/SliderFrame';
export function SliderFrameWithTagDemo() {
return (
<SliderFrame
format="horizontal"
className="max-w-380"
items={Array.from({ length: 5 }, (_, i) => ({
alt: `Mountain landscape ${i + 1}`,
src: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4',
}))}
labels={{ next: 'Next image', previous: 'Previous image' }}
>
<FrameLabelsWrapper hasImage>
<Tag
label="Best seller"
className="mx-12 mt-12 self-start px-8 sm:mx-24 sm:mt-24 sm:px-16"
/>
<FrameTitle className="w-full justify-between" hasImage>
<div>
<div className="text-b2 font-semibold">Mountain Resort</div>
<div className="text-b3">Winter</div>
</div>
<Button
aria-label="Explore Mountain Resort"
className="pointer-events-auto shrink-0"
color="white"
icon="ArrowDefaultRight"
theme="outline"
variant="circle"
/>
</FrameTitle>
</FrameLabelsWrapper>
</SliderFrame>
);
}
group-hover using Tailwind transitionsitems array skips the carousel entirely and renders a plain <img> — no embla overheadlabels to provide translated strings for accessibility; the button text is visually hidden (sr-only via ArrowButton)describedby connects the navigation buttons to a visible label elsewhere on the page for screen readers'use client' due to embla's hooks