# pinar: a small React Native carousel with accessibility built in

> Pinar is a React Native carousel for image sliders and onboarding flows that stays deliberately small, wrapping the platform ScrollView with pagination dots, prev and next controls, autoplay and accessibility labels. The README points you elsewhere the moment you need animations, lazy loading or parallax.

**kristerkari/pinar** — 🌲☀️ Customizable, lightweight React Native carousel component with accessibility support.

- Repository: https://github.com/kristerkari/pinar
- Stars: 640 · Forks: 12
- Language: TypeScript
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/kristerkari-pinar

## A carousel scoped to what a carousel should do

The project description is a single line: customizable, lightweight React Native carousel component with accessibility support. The README repeats it and then draws the boundary, which is unusual and useful.

Pinar is described as working well when creating simple image sliders or app onboarding flows. Those are the two use cases it is built for, and both are cases where the carousel is a row of views the user swipes through. The README then names the cases where you should use something else: if you need more advanced things like animations, lazy loading of images, or parallax, it suggests a library such as react-native-reanimated-carousel instead.

That framing matters more than the feature list. Most carousel packages in this space try to be the whole solution and end up carrying an animation runtime, an image pipeline and a gesture system with them. Pinar's bet is that a large share of apps need none of that, and that the platform's own ScrollView is enough.

The implementation follows that line. The package entry point is dist/src/index.js, the source is TypeScript, the license is MIT, and the repository ships type definitions in index.d.ts. The topics list a11y alongside react-native, carousel, slider and swiper, which matches the emphasis in the README.

## Thirteen properties and their defaults

The property table is where you can judge the design, because the defaults are what you get if you write <Carousel> and stop.

The defaults lean towards a plain slider. horizontal is true, loop is false, index starts at 0, showsControls and showsDots are both true, autoplay is false, and autoplayInterval is 3000 milliseconds. Width and height are unspecified by default, and the table explains that an unspecified value enables fullscreen mode through flex: 1.

The accessibility block is the part that sets this component apart from most. accessibility defaults to true, and the documentation marks setting it to false as not recommended. The labels for the previous and next buttons default to the strings Previous and Next, and both are configurable, which matters because a screen reader announcing an unlabelled arrow button is a common failure in carousels.

One more property deserves a note. mergeStyles defaults to false. When it is false your styles replace the defaults rather than merging with them, so a caller who sets a background colour without enabling the flag may find other default styling gone as well. Enabling mergeStyles is the switch that keeps the library's own layout while applying yours.

None of this is configurable through a theme provider or a stylesheet file. It is all props.

## It is a ScrollView with controls and a ref

The callback table makes the underlying mechanism obvious. Pinar exposes onScroll and onMomentumScrollEnd, which are the events of React Native's ScrollView, plus onLayout for the main wrapper View and onIndexChanged, which receives an object with index and total.

There is also a table of properties of <ScrollView />, meaning any ScrollView prop can be passed straight through to the underlying scroll view. That is the mechanism behind the name: Pinar is a controlled wrapper around the platform scroll view, with pagination dots, prev and next buttons, autoplay and an accessibility layer added on top.

Imperative control is exposed through a ref, and the README is explicit that to use the methods you need a reference to the carousel inside your React class component:

```jsx
<Carousel
  ref={carousel => {
    this.carousel = carousel;
  }}
/>
```

The method is then called from outside the carousel, for example from a button handler:

```jsx
<Button
  title="scroll to next page"
  onPress={() => {
    this.carousel.scrollToNext();
  }}
/>
```

Two practical notes. The documented usage is a class component with a callback ref, which is the older React pattern, so functional components will need a different ref approach than the one shown. And the methods table in the README is cut short, so the full list of available methods beyond scrollToNext is something you would confirm in the documentation rather than assume.

## Installing the package and rendering three slides

Installation is a single package manager call, and the README gives both forms:

```sh
yarn add pinar --save

## or
## npm install pinar --save
```

A minimal carousel is then a default export that renders the Carousel component with one child view per slide. The import block at the top of the example pulls in React, the Text, View and StyleSheet primitives from react-native, and the component itself from pinar:

```jsx
import React from "react";
import { Text, View, StyleSheet } from "react-native";
import Carousel from "pinar";
```

The component in the example defines three styles with StyleSheet.create, one per slide, each with flex: 1 and a different background colour, and a shared text style. The rendered part is short:

```jsx
export default () => (
  <Carousel>
    <View style={styles.slide1}>
      <Text style={styles.text}>1</Text>
    </View>
    <View style={styles.slide2}>
      <Text style={styles.text}>2</Text>
    </View>
    <View style={styles.slide3}>
      <Text style={styles.text}>3</Text>
    </View>
  </Carousel>
);
```

You should see three full-screen slides with pagination dots and prev and next controls. The examples folder in the repository holds a React Native app with the carousel used with many different options, and a components folder with example components if you would rather read them than run the app.

## What Pinar gives up next to an animation-driven carousel

The alternative the README names is react-native-reanimated-carousel, and the difference in approach is the same difference in ambition.

Pinar builds on the platform ScrollView. Gestures, momentum and paging come from the operating system component, and Pinar adds the parts an app needs on top: dots, controls, autoplay, an index callback and accessible labels. There is no animation runtime in the dependency list, no per-item render configuration for animating in and out, and no image loader, which is why the README can call it lightweight without hedging.

The alternative is built for the case where the carousel is a hero section rather than an onboarding step. When every slide animates, when images must load lazily as they come into view, or when a parallax effect carries background and foreground at different speeds, the ScrollView plus props model stops being enough and a dedicated animation library takes over. You accept a larger dependency and a different API in exchange for effects that Pinar does not attempt.

The choice is about what the carousel is for. Onboarding screens and simple promotional sliders are the same problem Pinar solves well. A product gallery where images slide, scale and parallax is a different problem, and the project itself is candid enough to send you elsewhere for it.

## patch-package on install and a slow release cadence

One line in package.json deserves attention before you add this to a project. The postinstall script runs patch-package, which means installing Pinar executes a script that applies patches from the package. That is a common pattern in the React Native ecosystem, where libraries need to adjust files inside node_modules, but it is also a build pipeline behaviour that security reviews flag, and you should know about it before an install runs in CI.

The rest of the scripts show a normally maintained project. build runs tsc --outDir dist, test runs jest, lint runs eslint over TypeScript and TSX files, functional runs detox for end-to-end tests on an iOS simulator configuration, and prepare runs husky install. The repository itself contains a src/ directory, an e2e/ directory, an examples app, an index.d.ts, a CHANGELOG.md and an AGENTS.md file, with unit and end-to-end test badges on the README.

The published history is the thing to weigh. Versions 0.12.0 and 0.12.1 both landed on 2021-07-11, and 0.12.2 followed on 2023-04-24. The package.json still reports 0.12.2, while the last push was on 2026-05-09, so commits are landing without a new release tag. Under semantic versioning, a 0.x version carries no compatibility promise, so treat the API as able to move and pin the version you validate.

The licence is MIT, which covers commercial use and modification without conditions beyond keeping the notice.

## Conclusion

Pinar fits a React Native team that needs a straightforward carousel for onboarding or an image slider, wants accessibility labels on the controls out of the box, and would rather depend on the platform ScrollView than on an animation runtime. It is the wrong choice for a product carousel that needs per-item animations, lazy image loading or parallax, since the README itself points to react-native-reanimated-carousel for those. Before adopting, check that the postinstall step running patch-package is acceptable in your build pipeline, pin the version you test because the latest published release is 0.12.2 from 2023-04-24 even though the last push was on 2026-05-09, and confirm the TypeScript types in index.d.ts match the React Native version you ship.

## FAQ

### How do I install Pinar in a React Native project?

Add it with yarn add pinar --save or npm install pinar --save. The package runs patch-package on postinstall, so your install pipeline will execute that script.

### Does Pinar support accessibility?

Yes. The accessibility property defaults to true and the README marks disabling it as not recommended. The prev and next buttons have configurable labels, accessibilityLabelPrev and accessibilityLabelNext, defaulting to Previous and Next.

### When should I not use Pinar for a carousel?

The README says to consider a library such as react-native-reanimated-carousel instead if you need animations, lazy loading of images or parallax. Pinar is aimed at simple image sliders and app onboarding flows.

### How do I control the Pinar carousel from outside the component?

Take a ref to the carousel inside your React class component and call the methods on it, for example this.carousel.scrollToNext() from a button handler. The README lists onIndexChanged, onLayout, onScroll and onMomentumScrollEnd as the callbacks, and ScrollView properties are passed through.

## Sources

- [Issues](https://github.com/kristerkari/pinar/issues)
- [kristerkari/pinar on GitHub](https://github.com/kristerkari/pinar)
- [License: MIT](https://github.com/kristerkari/pinar/blob/master/LICENSE)
- [README](https://github.com/kristerkari/pinar/blob/master/README.md)
- [Releases](https://github.com/kristerkari/pinar/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/kristerkari-pinar
