Skip to content

Latest commit

 

History

History
138 lines (110 loc) · 4.6 KB

README.md

File metadata and controls

138 lines (110 loc) · 4.6 KB

React Headless Gallery

Headless, zero-dependencies, gallery/carousel component.

Features

  • Infinite sliding (circular gallery)
  • Sliding animation (configurable)
  • Self looping (configurable)
  • Gallery indicators
  • Allows for lazy loading of gallery items (see example below)
  • Freely style and position all elements of the component
  • Built with accessibility in mind (see accessibility below)

Install

npm install react-headless-gallery
yarn add react-headless-gallery

Example

Click here for a live demo

Gallery demo

Code Example

The following code example uses TailwindCSS to style the gallery, as shown in the image above:

function MyGallery() {
  const items = [
    {
      id: 1,
      content: (
        <img alt="Item 1" src="..." />
      ),
    },
    {
      id: 2,
      content: (
        <img alt="Item 2" loading="lazy" src="..." />
      ),
    },
    {
      id: 3,
      content: (
        <img alt="Item 3" loading="lazy" src="..." />
      ),
    },
  ] as const;

  return (
    <div className="w-full h-full bg-white p-32">
      <Gallery className="flex flex-col items-center gap-4">
        <div className="flex flex-row gap-2 items-center">
          <Gallery.Prev className="cursor-pointer text-gray-800">
            <LeftSVG />
          </Gallery.Prev>
          <Gallery.Items className="w-[640px]">
            {items.map((item) => (
              <Gallery.Item key={item.id}>
                {item.content}
              </Gallery.Item>
            ))}
          </Gallery.Items>
          <Gallery.Next className="cursor-pointer text-gray-800">
            <RightSVG />
          </Gallery.Next>
        </div>
        <div className="flex flex-row gap-2">
          {[...Array(items.length)].map((_, i) => (
            <Gallery.Indicator
              key={i}
              galleryItemIndex={i}
              className={(isCurrent) =>
                `text-sm cursor-pointer ${isCurrent ? "text-gray-800" : "text-gray-300"}`
              }
            ></Gallery.Indicator>
          ))}
        </div>
      </Gallery>
    </div>
  );
}

Accessibility

The gallery's controls (next, prev, and indicators) are buttons with ARIA labels that can be changed. They are defined as controlling the gallery container with the aria-controls attribute. Please note that all items in the gallery will have the aria-hidden attribute, except for the item that is currently being shown. Items in the gallery should not include focusable elements.

API

Gallery

Name Type Description
transitionDurationMS number The duration of the transition in milliseconds. Default: 300.
transitionTimingFunction EasingFunction The timing function for the transition. Default: ease-in-out.
selfLooping false | number Enable self-looping. If a number is provided, it will be used as the looping interval in milliseconds. Default: false
stopLoopingOnInteraction boolean If true, self looping will stop when the gallery is interacted with (default: true)
className string Additional CSS classes to apply to the component.
style React.CSSProperties Inline styles to apply to the component.
ref React.Ref<HTMLDivElement> ref object to the HTML container element.

Gallery.Indicator

Name Type Description
galleryItemIndex number The index of the item to switch to.
aria-label string | ((itemNumber: number, isCurrent: boolean) => string) ARIA label for the button.
className string | ((isCurrent: boolean) => string) Additional CSS classes to apply to the component.
style React.CSSProperties Inline styles to apply to the button.
ref React.Ref<HTMLButtonElement> ref object to the HTML button element.

Gallery.Prev and Gallery.Next

Name Type Description
aria-label string ARIA label for the button.
className string Additional CSS classes to apply to the component.
style React.CSSProperties Inline styles to apply to the button.
ref React.Ref<HTMLButtonElement> ref object to the HTML button element.

Note on infinite sliding

To implement infinite sliding, the first and last gallery elements are cloned - each will appear twice in the DOM. If that causes undesirable side effects, please create an issue.