Image Accordion
A row of pictures where one opens wide and the rest wait as slim strips, each with a caption.
import { ImageAccordion, ImageAccordionItem } from '@youj/react'
Installation & usage
npm i @youj/reactFor an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.
Use an image accordion to show a handful of pictures in the room of one: destinations, product shots, case studies. One panel is open wide with its title and a short line; the others stay visible as strips, so the whole set reads at a glance. For a long sequence to step through, use a Carousel.
import { ImageAccordion, type ImageAccordionItem } from '@youj/react'
const places: ImageAccordionItem[] = [
{ id: 'coast', media: { src: '/coast.jpg', alt: 'Coast road at sunrise' }, title: 'Coast road', description: 'Morning light over the headland' },
{ id: 'dunes', media: { src: '/dunes.jpg', alt: 'Sand dunes at dusk' }, title: 'Dunes', description: 'Wind-cut ridges at dusk' },
{ id: 'valley', media: <MyIllustration />, title: 'Valley' },
]
<ImageAccordion items={places} />media is { src, alt } for an image (it covers the panel) or any node: an illustration, a video, a gradient. The first panel is open at first; value, defaultValue and onValueChange hold the open id.
With activation="hover" (the default) a panel opens when the pointer rests on it or it takes focus, and on touch when it's tapped. activation="click" opens only on a press, Enter or Space, and hover and the arrow keys just point. orientation="vertical" stacks the panels.
The component keeps its size: the panels share its box (h-80 across, h-120 stacked), so opening one only moves the split. Set your own height with className.
Description
Six product shots, each { src, alt }. Point at a strip, focus it or tap it to open it; the open panel shows its caption.
Code
image-accordion-demo.tsx, the Demo story. The component itself comes from the package.
Reference
Propsitems, value, activation, orientation… (7)
Props
| Prop | Type | |
|---|---|---|
itemsRequired | ImageAccordionItem[] | – |
value | stringThe open panel's id (controlled). | – |
defaultValue | stringThe panel open at first. Default: the first. | – |
onValueChange | (id: string) => voidCalled with the id of the panel that opens. | – |
activation | 'hover' | 'click'
default 'hover' | 'hover' |
orientation | 'horizontal' | 'vertical'Panels side by side ( default 'horizontal' | 'horizontal' |
aria-label | stringNames the group. Default: the labels' "Gallery". | – |
sound | booleanWith sound on ( default true | true |
Other props pass through: extends ComponentProps<'div'>. | ||
Items
| Prop | Type | |
|---|---|---|
idRequired | string | – |
mediaRequired | ReactNode | { src: string; alt: string }The picture: | – |
titleRequired | ReactNodeThe caption's first line, and the panel's accessible name. | – |
description | ReactNodeA short line under the title. | – |
StylingParts and data attributes
Styling
Parts: image-accordion (with data-orientation horizontal or vertical and data-yj-activation hover or click), image-accordion-panel (with data-state active or inactive), image-accordion-media, image-accordion-caption, image-accordion-title and image-accordion-description.
MotionSplit, caption, strips · reduced motion
Motion
| Moment | Tokens | ||
|---|---|---|---|
| Splitthe opening panel widens as the others narrow, retargeting mid-glide | spring.smooth0.36s, bounce 0 | 0.36s, bounce 0 | |
| Captionfades up once its panel has started to open | duration.baseease.enter220ms · cubic-bezier(0.16, 1, 0.3, 1) | 220mscubic-bezier(0.16, 1, 0.3, 1) | |
| Stripssit a little quieter, and brighten under the pointer | duration.baseease.standard220ms · cubic-bezier(0.2, 0, 0, 1) | 220mscubic-bezier(0.2, 0, 0, 1) |
Reduced motion
The split and the caption jump.
Sound
With sound on (YoujProvider's sound), opening a panel by a press or a key plays select; hovering stays silent. sound={false} keeps one accordion quiet.
Reduced motion
The split and the caption jump; nothing glides.
AccessibilityGroup, buttons, keys
Accessibility
- It is a
groupnamed "Gallery" (imageAccordionin the labels), or youraria-label. - Each panel is a button named by its title and described by its line; the open one carries
aria-current. Captions stay in the page for screen readers whichever panel is open. - The panels are one tab stop. The arrow keys of the orientation move between them (Left and Right across, mirrored in RTL; Up and Down stacked), and Home and End go to the first and last. In hover mode focus opens the panel; in click mode Enter or Space does.
- Give each image its
alt, or yourmediaits own name if it carries meaning.