Open-source project
kuraydev/react-native-bouncy-checkbox avatar
kuraydev/react-native-bouncy-checkbox

react-native-bouncy-checkbox animates a checkbox without adding dependencies

Fully customizable animated bouncy checkbox for React Native

870 stars57 forksTypeScriptMIT

At a glance

What is it?
react-native-bouncy-checkbox is a TypeScript React Native component that renders a bouncing check box with configurable colors, icons and labels, and it can either keep its own state or hand control back to your component. It is a single-purpose UI component, and the state model it settled on in version 4.1.2 is the part you have to understand before using it.
Who is it for?
Use react-native-bouncy-checkbox when you want one animated check box with a configurable icon, color and label in a React Native app, and when you are happy with a component that owns its own state unless you pass isChecked with useBuiltInState set to false. Do not use it for a multi-select list, a switch, or a control that needs an indeterminate or disabled state, since none of those appear in the documented property list.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 69 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A single animated control with no dependencies of its own

react-native-bouncy-checkbox is a React Native component for a check box that bounces when you press it. The package describes itself as a fully customizable animated bouncy checkbox, and the repository states that it has zero dependencies, meaning nothing is pulled into your node_modules alongside it.

The audience is narrow and that is the point. A design team that has decided the check box should feel playful, with a springy press animation rather than a static tick, can take the component and restyle it with colors, a custom icon and a label, instead of writing the animation with React Native's own Animated API and maintaining it over time.

What you do not get is a family of controls. There is no switch, no radio group and no list mode in the documented property list. This is one component that renders one box, and it earns its place in an app when that single interaction is the point.

The package is written in TypeScript, ships type definitions, and the repository contains an example folder with an App.tsx plus a second exampleManual folder, so the intended way to learn the API is by reading working code.

useBuiltInState and isChecked decide who owns the tick

Version 4.1.2 was a rewrite into a modern functional component refactored with React hooks, and it changed the state model. The release notes list the headline changes: imperative handle support, a controllable isChecked prop, onLongPress and testID support, and the removal of the older disableBuiltInState prop.

What replaced disableBuiltInState is useBuiltInState. By default the component keeps its own checked state and drives itself. Set useBuiltInState to false and pass the current value in through isChecked, and the component becomes fully controlled: your state is the source of truth, and the onPress callback hands you the next boolean to store.

The README is explicit that these two values have to agree. In the controlled example, the comment inside the handler notes that the checked argument and the local state value should be the same value, which is a hint about how the component reports the press: onPress fires after the bounce effect and receives the next isChecked boolean when the built-in state is off.

That ordering matters for form-like screens. Because the callback arrives after the animation, code that flips a parent state and expects an instant visual response will see the box animate first.

The property table, and the unfillColor spelling trap

The documented props cover four things: state, appearance, the icon and the label.

For appearance, size sets the width and height and defaults to 25, fillColor changes the filled color and defaults to #f09f48, and unfillColor changes the color when the box is not checked and defaults to transparent. Style props exist for the container, the text, the outer icon container and the inner icon container, so most visual tweaks are a style object rather than a new component.

For content, text takes a string, textComponent takes a React component, and disableText hides the label entirely. iconComponent replaces the default Icon, and checkIconImageSource sets your own check icon image.

Here is the trap worth catching early. The property table names the prop unfillColor, while the advanced usage example in the same README writes unFillColor with a capital F. If you copy the example you get a prop the table does not list, and the unfilled color stays at its default. The prop names for the other colors follow the lowercase form, fillColor and unfillColor, so treat the capitalised variant in the snippet as an error.

The same table also documents that onPress and onLongPress both fire after the bounce effect and both receive the next isChecked boolean.

Installing the package and rendering the first box

The package is on npm and the install step is a single dependency:

bash
npm i react-native-bouncy-checkbox

Then import the component:

js
import BouncyCheckbox from "react-native-bouncy-checkbox";

The simplest usage is a single element with a press handler:

js
<BouncyCheckbox onPress={(isChecked: boolean) => {}} />

The advanced example shows how the styling props fit together:

tsx
<BouncyCheckbox
  size={25}
  fillColor="red"
  unFillColor="#FFFFFF"
  text="Custom Checkbox"
  iconStyle={{ borderColor: "red" }}
  innerIconStyle={{ borderWidth: 2 }}
  textStyle={{ fontFamily: "JosefinSans-Regular" }}
  onPress={(isChecked: boolean) => {console.log(isChecked)}}
/>

Note that this snippet uses the capitalised unFillColor again, so copy the rest of the example rather than that line. The package entry point in package.json is ./build/dist/index.js, and the published files are the build output plus the lib folder, so the component ships compiled rather than as raw source.

Handing the state back to your own component

The controlled pattern is the one to reach for when the check box is part of a form, a settings row or anything that must reflect server state. You keep a React state variable, pass it down, and update it inside the press handler.

tsx
const [localChecked, setLocalChecked] = React.useState(false);

 <BouncyCheckbox
   isChecked={localChecked}
   disableText
   fillColor="green"
   size={50}
   useBuiltInState={false}
   iconImageStyle={styles.iconImageStyle}
   iconStyle={{borderColor: 'green'}}
   onPress={(checked: boolean) => {
         // These two should be same value
         console.log('::Checked::', checked);
         console.log('::LocalChecked::', localChecked);
         setLocalChecked(!localChecked);
   }}
/>

Two things stand out. The state variable starts false and is set with the negation on press, and the handler logs the value the component reported next to the value it currently holds, which is exactly the mismatch the comment warns about: after setLocalChecked runs, localChecked in that closure is still the previous value.

The example also uses an iconImageStyle prop, which is not in the property table, and the disableText prop, which is. That mix is a good reason to check your usage against the table rather than against the snippets.

The same example disables the label and enlarges the box to 50, which shows the component is usable as a bare tick without any text next to it.

What the component does not cover

The documented property list has no entry for an indeterminate state, no disabled prop, and no accessibility props such as an accessibilityLabel or a role. testID support appears among the 4.1.2 changes, so you can locate the component in tests, but the animation and the label still have to reach a screen reader through whatever you pass around it.

The animation itself is not parameterised. The 4.1.2 notes mention customizable animation options, yet the visible property table exposes no duration, damping or spring constants. Whatever tuning exists is inside the component, which means a designer asking for a slower or tighter bounce has no documented prop to turn.

There is also no documented support for lists. Rendering many of these in a settings screen is possible, but each instance animates independently and the package offers no list specific behaviour.

The fairest way to think about it is as a styled, animated leaf control with two state models. If your requirement is a multi-select list or a form field with validation and error states, this component is the wrong size and you will spend more time working around it than it saves.

The real alternative is to build the control yourself on top of React Native's own primitives: a pressable, an animated value and a check icon of your choosing. The difference in approach is ownership. Building it yourself means you set the spring parameters, the accessibility props and the disabled behaviour exactly as your design system wants them, and you carry the maintenance. Taking the component means the bounce, the default colors and the two state modes arrive on the first render, and you accept that the animation tuning is not yours to change. Teams with an existing component library and a strict design system usually do not need a third option here, and teams with no design system at all can start from this one.

Releases, provenance and the MIT licence

Version numbers and dates tell a mixed story. Version 4.1.2, the rewrite that introduced the current state model, was published on 2024-08-21. Versions 4.1.3 and 4.1.4 followed in quick succession on 2026-01-04 and 2026-01-07, and the last push to the default branch was on 2026-08-16. The repository is not archived.

The README headline still announces 4.1.2 as the current feature release while package.json carries the version 4.1.4, so the changelog in the README lags the published package. Release handling is automated: semantic-release and commitlint with conventional commits are development dependencies, husky and lint-staged run pre-commit checks, prettier formats the code and eslint with the React Native config lints it.

Provenance deserves a look. The repository under kuraydev carries a homepage and a bugs URL that point at WrathChaos/react-native-bouncy-checkbox, and the repository field in package.json points at the same owner, while the author is listed as Kuray (FreakyCoder). The npm package name is react-native-bouncy-checkbox, and the two owners in the metadata mean you should check which repository a given release came from before filing an issue.

The licence is MIT, which permits use in commercial and closed applications and requires the copyright notice and permission text to travel with the package.

Editorial conclusion

Use react-native-bouncy-checkbox when you want one animated check box with a configurable icon, color and label in a React Native app, and when you are happy with a component that owns its own state unless you pass isChecked with useBuiltInState set to false. Do not use it for a multi-select list, a switch, or a control that needs an indeterminate or disabled state, since none of those appear in the documented property list. Before you adopt it, read the prop table against your own code and check the two spellings of the unfilled color prop, then run the example app in the example folder to see the bounce on your target devices, because the animation parameters are not exposed as props.

Frequently asked questions

How do I install react-native-bouncy-checkbox?

Add it with npm i react-native-bouncy-checkbox and import it as import BouncyCheckbox from "react-native-bouncy-checkbox". The README states the package has zero dependencies of its own.

How do I control the checked state of react-native-bouncy-checkbox from my own component?

Set useBuiltInState to false and pass your own value through the isChecked prop, then update that state inside the onPress handler. The README example notes that the value reported by the callback and your own state should be the same value.

What is the difference between the isChecked and useBuiltInState props?

isChecked carries the current checked value into the component, while useBuiltInState set to false tells the component to stop keeping its own state and let yours decide. The 4.1.2 release notes list the removal of the older disableBuiltInState prop in favour of this model.

What are the default size and colors of the bouncy checkbox?

The property table lists size with a default of 25 for width and height, fillColor with a default of #f09f48, and unfillColor with a default of transparent. The README example writes the last one as unFillColor, so the capitalised spelling in the snippet does not match the table.

Official sources

  1. kuraydev/react-native-bouncy-checkbox on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/kuraydev-react-native-bouncy-checkbox.svg)](https://hysenlabs.com/projects/kuraydev-react-native-bouncy-checkbox)

Was this useful?