# Pure React Carousel makes you assemble the DOM, and asks for index={0}

> Pure React Carousel is an MIT TypeScript React carousel library with zero runtime dependencies, built from functional components and React Context rather than wrapping a jQuery carousel. It ships a stylesheet, requires Node 22 to build, and lets you place its components in any order you like.

**express-labs/pure-react-carousel** — A highly impartial suite of React components that can be assembled by the consumer to create a carousel with almost no limits on DOM structure or CSS styles.  If you're tired of fighting some other developer's CSS and DOM structure, this carousel is for you.

- Repository: https://github.com/express-labs/pure-react-carousel
- Website: https://express-labs.github.io/pure-react-carousel/
- Stars: 1,698 · Forks: 162
- Language: TypeScript
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/express-labs-pure-react-carousel

## The pitch is that there is nothing to override

Pure React Carousel is a suite of React components you assemble yourself, and the framing in the repository description is adversarial in a useful way: are you tired of fighting some other developer's CSS and DOM structure?

The list of motivations spells out what that means. It was developed from the ground up in React with modern functional components, hooks and native React Context. It is written in TypeScript with bundled type definitions and zero runtime dependencies. It is not a wrapper or port of a non-React carousel such as Slick or Flickity. It supports touch and mouse drag, is ARIA compliant and responsive by default.

Two constraints in that list are the actual design. You can assemble the carousel components in the DOM in any order you desire, so long as they are all children of a single CarouselProvider. And you can put any class names, properties, attributes or styles on any of the components you need.

The cost is that there is no default carousel. There is a tutorial, and it is six steps long, and step five of six is still your own JSX. For a team whose design system owns the markup, that is the point. For anyone else, it is a component library that arrives in pieces.

The library also supports both ES Modules and CommonJS, with separate Rollup builds for each.

## CarouselProvider is the only mandatory piece

All the components talk to each other through React Context provided by CarouselProvider, and it has three required properties: totalSlides, naturalSlideWidth and naturalSlideHeight.

```jsx
<CarouselProvider
  naturalSlideWidth={100}
  naturalSlideHeight={125}
  totalSlides={3}
/>
```

The two natural slide dimensions exist to create an aspect ratio for each slide, which is how a responsive carousel avoids knowing your viewport width in advance. The carousel is responsive by default and stretches to fill the width of its parent container, so those numbers are the ratio rather than the rendered size.

CarouselProvider must have children, and the ordering rule is loose: any order, but they all need to be inside that one provider. Some components still have ancestor and descendant relationships, and Slide has to be inside a Slider, but they need not be direct relatives, which is what lets you put a caption or a counter between the slider and the controls.

Slide carries the one prop that trips people up. It requires a sequentially numbered index prop starting at zero, and since you will usually map over data, you pass the index from your loop.

## The component list is wider than a carousel needs

Reading the component list tells you how much of the interaction vocabulary the library intends to own.

Beyond CarouselProvider, Slider and Slide, there are Dot and DotGroup for pagination, Image and ImageWithZoom for slide content with an optional zoom interaction, Spinner for a loading state, four navigation buttons, ButtonBack, ButtonNext, ButtonFirst and ButtonLast, and ButtonPlay for autoplay control.

That set is a design decision as much as a feature list. Shipping ButtonFirst and ButtonLast rather than only next and previous means the library assumes you may want a carousel that starts from the beginning, which is common in galleries and uncommon in marketing carousels. Spinner is the least replaceable of the set, because a loading indicator inside a slide is usually a design-system concern, and it is provided anyway.

There is also a hooks and context layer, useContext, and a higher order component called WithStore(). That gives three ways to reach the carousel state: the documented hooks, the HOC, and an advanced pattern the README calls accessing the view components directly, which is for reaching the underlying rendered elements when the context is not enough.

For TypeScript users, each of these is documented separately in a TypeScript usage section covering the hooks, the HOC and examples.

## Styles come from one file you import, or from you

The install step is deliberately small, and the styling step is where the library's opinion appears.

```bash
npm i -S pure-react-carousel
```

You import only the components you need:

```jsx
import { CarouselProvider, Slider, Slide, ButtonBack, ButtonNext } from 'pure-react-carousel';
```

Then, if you use a bundler such as Webpack, Vite or Rollup with a CSS loader, you import the stylesheet as well:

```jsx
import 'pure-react-carousel/dist/react-carousel.es.css';
```

So the library does ship CSS, and it is a single file with a predictable name. What it does not do is impose structure or styles you need to defeat, because the class names and attributes are yours to set.

That is a meaningful distinction. A carousel whose CSS uses fixed selectors and internal class names forces you into specificity battles or a fork. One that hands you components to place yourself leaves the layout to your own CSS, at the cost of writing the responsive rules.

The build side has been modernised as well. The package scripts use Rollup for both module formats, oxlint and oxfmt for linting and formatting, tsc --noEmit for typechecking, and vitest with coverage for tests, and the engines field requires Node 22.0.0 or newer to build.

## Version drift is the thing to check before adopting

Here is the fact that should drive the decision. The most recent published releases shown for the package are v1.30.1 from 2022-10-13, v1.30.0 from 2022-10-12 and v1.29.0 from 2022-07-28. The repository's package.json declares version 3.0.0, and the last push was on 2026-10-16 with the repository not archived.

So there is active work on a 3.0.0 line in the repository and a published 1.30.x on the registry. What you get from npm and what you see in the repository are different versions, and the README documents the API of the current tree.

The tooling in the tree is modern, which suggests a real 3.0 is close, and the presence of release-please configuration, a Rollup ES and CJS split, oxlint and Vitest all point at a rewritten build rather than a maintained 1.x.

Practical advice, then: check which version npm resolves before you write code against the documented API, and read the changelog for the version you actually get. A library this old in published form and this active in source is a normal risk for an unstyled component you own the markup for, and not much of one for a design-system team with a React version pinned.

The project is MIT licensed, supported by Express Labs, has a published Snyk badge for known vulnerabilities and a 100 percent test coverage claim in the README. Example code lives under src/App/examples, and a live documentation site with examples is published at the express-labs GitHub Pages site.

## Conclusion

Pure React Carousel suits a React team that has to live inside an existing design system, since the components emit no opinionated markup and take your class names and attributes. It is the wrong choice if you want a drop-in carousel in one component, because the assembly is your job, and it is a choice with a support cost: the last published release was v1.30.1 in 2022 while the repository has moved to version 3.0.0 in package.json. Verify which version you actually get from npm before depending on it, and remember every Slide needs a sequential index starting at zero.

## FAQ

### How do I install and use Pure React Carousel?

Run npm i -S pure-react-carousel, import the components you need from pure-react-carousel, and, if your bundler has a CSS loader, also import pure-react-carousel/dist/react-carousel.es.css. Everything must live inside a single CarouselProvider.

### What are the required props for CarouselProvider?

totalSlides, naturalSlideWidth and naturalSlideHeight. The two natural dimensions define the aspect ratio used for each slide, and CarouselProvider must also have children.

### Does Pure React Carousel depend on Slick or jQuery?

No. The README states it is not a wrapper or port of a non-React carousel such as Slick or Flickity, and package.json lists zero runtime dependencies.

## Sources

- [express-labs/pure-react-carousel on GitHub](https://github.com/express-labs/pure-react-carousel)
- [License: MIT](https://github.com/express-labs/pure-react-carousel/blob/master/LICENSE)
- [Project website](https://express-labs.github.io/pure-react-carousel/)
- [README](https://github.com/express-labs/pure-react-carousel/blob/master/README.md)
- [Releases](https://github.com/express-labs/pure-react-carousel/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/express-labs-pure-react-carousel
