---
title: Implement a checkbox
description: Learn how to implement a fully customizable checkbox in your Expo project.
---
import { SnackInline } from '~/ui/components/Snippet';
The [`expo-checkbox`](/versions/latest/sdk/checkbox/) package provides a quick implementation of a checkbox that you can directly use in your project. However, to have full customization, and control over the look and feel of the checkbox, this page goes in-depth on how to implement the component from scratch.
## Understanding the checkbox
A checkbox is a button that exists in one of two states — it is checked or it isn't. This makes it a perfect candidate for the `useState()` hook. Our first iteration will render a button that toggles between checked and unchecked states. When the checkbox is checked, we'll render a checkmark icon in the center of the button.
> You can find more information about using icons in your Expo project in our [Icons guide](/guides/icons).
```jsx
import { useState } from 'react';
import { Pressable, StyleSheet, Text, View } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
function MyCheckbox() {
const [checked, setChecked] = useState(false);
return (
setChecked(!checked)}>
{checked && }
);
}
export default function App() {
return (
Checkbox Example
{`⬅️ Click!`}
);
}
const styles = StyleSheet.create({
checkboxBase: {
width: 24,
height: 24,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 4,
borderWidth: 2,
borderColor: 'coral',
backgroundColor: 'transparent',
},
checkboxChecked: {
backgroundColor: 'coral',
},
appContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
appTitle: {
marginVertical: 16,
fontWeight: 'bold',
fontSize: 24,
},
checkboxContainer: {
flexDirection: 'row',
alignItems: 'center',
},
checkboxLabel: {
marginLeft: 8,
fontWeight: 500,
fontSize: 18,
},
});
```
> [icons.expo.fyi](https://icons.expo.fyi) is a great resource for finding all of the icons available in the `@expo/vector-icons` package.
## Controlling the checkbox
This checkbox isn't useful in this state because the `checked` value is accessible only from within the component — more often than not you'll want to control the checkbox from outside. This is achievable by defining `checked` and `onChange` as props that are passed into the checkbox:
{/* prettier-ignore */}
```jsx
import { useState } from 'react';
import { Pressable, StyleSheet, Text, View } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
function MyCheckbox({ /* @info Define checked and onChange as props instead of state */onChange, checked/* @end */ }) {
return (
{checked && }
);
}
export default function App() {
/* @info Move the checked and setChecked values outside of the checkbox component */
const [checked, setChecked] = useState(false);
/* @end */
return (
Checkbox Example
/* @info Pass the checked and onChange props to the checkbox */
setChecked(!checked)} checked={checked} />
/* @end */
{`⬅️ Click!`}
);
}
const styles = StyleSheet.create({
checkboxBase: {
width: 24,
height: 24,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 4,
borderWidth: 2,
borderColor: 'coral',
backgroundColor: 'transparent',
},
checkboxChecked: {
backgroundColor: 'coral',
},
appContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
appTitle: {
marginVertical: 16,
fontWeight: 'bold',
fontSize: 24,
},
checkboxContainer: {
flexDirection: 'row',
alignItems: 'center',
},
checkboxLabel: {
marginLeft: 8,
fontWeight: 500,
fontSize: 18,
},
});
```
> This pattern is referred to as a [controlled component](https://react.dev/learn/sharing-state-between-components#controlled-and-uncontrolled-components).
## Extending the interface
It's common enough to need to render different styles when the checkmark is `checked` and when it is not. Let's add this to the checkbox's props and make it more reusable:
```jsx
import { useState } from 'react';
import { Pressable, StyleSheet, Text, View } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
function MyCheckbox({
checked,
onChange,
/* @info Add style and icon props to make the checkbox reusable throughout your codebase */
buttonStyle = {},
activeButtonStyle = {},
inactiveButtonStyle = {},
activeIconProps = {},
inactiveIconProps = {},
/* @end */
}) {
/* @info Set icon props based on the checked value */
const iconProps = checked ? activeIconProps : inactiveIconProps;
/* @end */
return (
onChange(!checked)}>
{checked && (
)}
);
}
export default function App() {
const [checked, setChecked] = useState(false);
return (
Checkbox Example
{`⬅️ Click!`}
);
}
const styles = StyleSheet.create({
checkboxBase: {
width: 24,
height: 24,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 4,
borderWidth: 2,
borderColor: 'coral',
backgroundColor: 'transparent',
},
checkboxChecked: {
backgroundColor: 'coral',
},
appContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
appTitle: {
marginVertical: 16,
fontWeight: 'bold',
fontSize: 24,
},
checkboxContainer: {
flexDirection: 'row',
alignItems: 'center',
},
checkboxLabel: {
marginLeft: 8,
fontWeight: 500,
fontSize: 18,
},
});
```
This checkbox ticks all of the boxes of what it should be. It toggles between `checked` states, can be controlled, and the styles are fully customizable.