Promises

PreviousNext

An auto-advancing carousel showcasing brand promises, with a dot-progress indicator, previous/next navigation, and a mobile overlay menu for item selection

Beautiful beach destination
Discover
'use client';

import { Promises } from '@/ui/Promises/Promises';

export function PromisesDemo() {
  return (
    <Promises
      className="min-h-500 w-full"
      items={[
        {
          title: 'The most beautiful destinations',
          href: '#',
          image: {
            src: 'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=400',
            alt: 'Beautiful beach destination',
          },
        },
        {
          title: 'Kids club starting from 4 months',
          href: '#',
          image: {
            src: 'https://images.unsplash.com/photo-1529156069898-49953e39b3ac?w=400',
            alt: 'Kids playing at the club',
          },
        },
        {
          title: 'The best restaurants on the coast',
          href: '#',
          image: {
            src: 'https://images.unsplash.com/photo-1414235077428-338989a2e8c0?w=400',
            alt: 'Fine dining restaurant',
          },
        },
      ]}
      labels={{
        anchor: { continue: 'Discover' },
        layer: { close: 'Close menu', open: 'Open menu' },
        scroller: { previous: 'Previous', next: 'Next' },
      }}
    />
  );
}

Installation

npx shadcn@latest add https://develop.trident-ui.pro.clubmed/r/promises.json

Usage

import { Promises } from '@/ui/Promises/Promises';
 
export function Component() {
  return (
    <Promises
      items={[
        {
          title: 'The most beautiful destinations',
          href: '/destinations',
          image: { src: '/images/destinations.jpg', alt: 'Beach destination' },
        },
        {
          title: 'Kids club starting from 4 months',
          href: '/kids-club',
          image: { src: '/images/kids.jpg', alt: 'Kids at the club' },
        },
      ]}
      labels={{
        anchor: { continue: 'Discover' },
        layer: { close: 'Close menu', open: 'Open menu' },
        scroller: { previous: 'Previous', next: 'Next' },
      }}
    />
  );
}

Anatomy

Promises is composed of three internal sub-components that are exported for advanced use:

Sub-componentRole
PromisesMediaStacked image slides with a progress dot bar and prev/next controls
PromisesMenuTitle list — overlay on mobile, sidebar at @3xl container width

API Reference

Promises

PropTypeDefaultDescription
itemsPromisesItem[]RequiredArray of carousel items (title, href, image)
labelsPromisesLabelsRequiredLocalised strings for the anchor, layer toggle, and scroller
classNamestringundefinedAdditional CSS classes applied to the root container

PromisesItem

FieldTypeDefaultDescription
titlestringRequiredTitle displayed on the media overlay and in the menu
hrefstringRequiredURL the "continue" anchor links to
imageImagePropsRequiredProps forwarded to the trident-ui Image component
idstringundefinedOptional stable id; used for accessible labelling

PromisesLabels

FieldTypeDescription
anchor.continuestringLabel for the "continue" anchor inside each item
layer.openstringAria-label for the toggle button (closed state)
layer.closestringAria-label for the toggle button (open state)
scroller.previousstringScreen-reader label for the previous button
scroller.nextstringScreen-reader label for the next button

Behaviour

Auto-advance

Items cycle automatically every 10 seconds. The timer resets whenever the user interacts with the previous/next buttons or the dot indicators. The interval clears on unmount.

Responsive layout

Promises uses a CSS container named promises. Below @3xl the menu is an overlay (toggle with the up-arrow button). At @3xl and above the menu becomes a static sidebar and the toggle button is hidden.

Dot progress bar

Each dot animates a fill from left to right over 10 s (animate-filling) while that item is active. Dots for past items are filled white; future items show at 40 % opacity.

Accessibility

  • Each image slide is an <article> with aria-hidden and inert when not active — screen readers and keyboard focus skip inactive slides.
  • The media region carries aria-hidden / inert when the overlay menu is open, preventing accidental focus trap on the hidden layer.
  • Previous and next buttons expose their purpose through sr-only text taken from labels.scroller.
  • The overlay toggle button updates its aria-label between labels.layer.open and labels.layer.close to communicate the current menu state.
  • Dot indicator buttons carry aria-current to announce the active slide to assistive technology.

Notes

  • All three files (Promises, PromisesMedia, PromisesMenu) are marked 'use client' — they rely on useState, useEffect, and useCallback.
  • PromisesMedia and PromisesMenu are internal sub-components; import Promises to consume the full organism.
  • @3xl/promises: container-query modifiers require @tailwindcss/container-queries. The @container/promises class is added to the root <div> automatically.