ExpoStartup

Checkbox

A customizable checkbox component for boolean selection inputs.

Checkbox

The Checkbox component provides a way for users to make binary (on/off) selections. It's commonly used in forms for accepting terms, enabling settings, or selecting options.

Features

  • Simple Interface: Clean checkbox with accompanying label
  • Controlled Component: Easily manage checked state in parent components
  • Error Handling: Displays error messages for validation
  • Custom Styling: Accepts additional classes for customization
  • Dark Mode Support: Automatic light/dark mode styles

Import

import Checkbox from '@/components/forms/Checkbox';

Props

PropTypeDefaultDescription
checkedbooleanfalseWhether the checkbox is checked
onChange(checked: boolean) => voidRequiredFunction called when checkbox state changes
labelstringRequiredText label for the checkbox
errorstringError message to display
classNamestring''Additional Tailwind classes for the container

Usage Examples

Basic Checkbox

import React, { useState } from 'react';
import { View } from 'react-native';
import Checkbox from '../components/forms/Checkbox';
 
function CheckboxExample() {
  const [isChecked, setIsChecked] = useState(false);
  
  return (
    <Checkbox
      checked={isChecked}
      onChange={setIsChecked}
      label="I agree to the terms and conditions"
    />
  );
}

Checkbox with Error State

function ValidatedCheckbox() {
  const [termsAccepted, setTermsAccepted] = useState(false);
  const [error, setError] = useState('');
  
  const handleChange = (checked) => {
    setTermsAccepted(checked);
    if (!checked) {
      setError('You must accept the terms to continue');
    } else {
      setError('');
    }
  };
  
  return (
    <Checkbox
      checked={termsAccepted}
      onChange={handleChange}
      label="I agree to the terms and conditions"
      error={error}
    />
  );
}

Multiple Checkboxes

function PreferencesForm() {
  const [emailNotifications, setEmailNotifications] = useState(false);
  const [pushNotifications, setPushNotifications] = useState(false);
  const [marketingEmails, setMarketingEmails] = useState(false);
  
  return (
    <View className="space-y-2">
      <Checkbox
        checked={emailNotifications}
        onChange={setEmailNotifications}
        label="Email notifications"
      />
      
      <Checkbox
        checked={pushNotifications}
        onChange={setPushNotifications}
        label="Push notifications"
      />
      
      <Checkbox
        checked={marketingEmails}
        onChange={setMarketingEmails}
        label="Marketing emails"
      />
    </View>
  );
}

Custom Styled Checkbox

<Checkbox
  checked={isSubscribed}
  onChange={setIsSubscribed}
  label="Subscribe to newsletter"
  className="mb-6 bg-gray-100 p-3 rounded-md"
/>

Integration Examples

Form Validation

import React, { useState } from 'react';
import { View, Text, Alert } from 'react-native';
import Input from '../components/forms/Input';
import Checkbox from '../components/forms/Checkbox';
import Button from '../components/Button';
 
function SignupForm() {
  const [form, setForm] = useState({
    name: '',
    email: '',
    agreeToTerms: false
  });
  
  const [errors, setErrors] = useState({
    name: '',
    email: '',
    agreeToTerms: ''
  });
  
  const handleSubmit = () => {
    let isValid = true;
    const newErrors = { name: '', email: '', agreeToTerms: '' };
    
    if (!form.name) {
      newErrors.name = 'Name is required';
      isValid = false;
    }
    
    if (!form.email) {
      newErrors.email = 'Email is required';
      isValid = false;
    } else if (!form.email.includes('@')) {
      newErrors.email = 'Please enter a valid email';
      isValid = false;
    }
    
    if (!form.agreeToTerms) {
      newErrors.agreeToTerms = 'You must agree to the terms';
      isValid = false;
    }
    
    setErrors(newErrors);
    
    if (isValid) {
      Alert.alert('Success', 'Form submitted successfully!');
      // Submit form data
    }
  };
  
  return (
    <View className="p-4">
      <Input
        label="Full Name"
        value={form.name}
        onChangeText={(text) => setForm({ ...form, name: text })}
        error={errors.name}
      />
      
      <Input
        label="Email"
        value={form.email}
        onChangeText={(text) => setForm({ ...form, email: text })}
        keyboardType="email-address"
        error={errors.email}
      />
      
      <Checkbox
        checked={form.agreeToTerms}
        onChange={(checked) => setForm({ ...form, agreeToTerms: checked })}
        label="I agree to the terms and privacy policy"
        error={errors.agreeToTerms}
      />
      
      <Button 
        title="Sign Up" 
        onPress={handleSubmit}
        className="mt-4"
      />
    </View>
  );
}

Settings Screen Example

function NotificationSettings() {
  const [settings, setSettings] = useState({
    pushEnabled: true,
    emailEnabled: false,
    marketingEnabled: false,
    updatesEnabled: true
  });
  
  const updateSetting = (key, value) => {
    setSettings({
      ...settings,
      [key]: value
    });
    
    // In a real app, you might save to API or local storage
    console.log(`Setting ${key} changed to ${value}`);
  };
  
  return (
    <View className="p-4">
      <Text className="text-xl font-bold mb-4">Notification Preferences</Text>
      
      <View className="space-y-3">
        <Checkbox
          checked={settings.pushEnabled}
          onChange={(checked) => updateSetting('pushEnabled', checked)}
          label="Push Notifications"
        />
        
        <Checkbox
          checked={settings.emailEnabled}
          onChange={(checked) => updateSetting('emailEnabled', checked)}
          label="Email Notifications"
        />
        
        <Checkbox
          checked={settings.updatesEnabled}
          onChange={(checked) => updateSetting('updatesEnabled', checked)}
          label="App Updates"
        />
        
        <Checkbox
          checked={settings.marketingEnabled}
          onChange={(checked) => updateSetting('marketingEnabled', checked)}
          label="Marketing Communications"
        />
      </View>
      
      <Text className="text-sm text-gray-500 mt-4">
        You can change these settings at any time from your account preferences.
      </Text>
    </View>
  );
}

Building a Checkbox List Component

If you need to manage a group of related checkboxes, you can create a simple wrapper component:

function CheckboxList({ options, selectedValues, onChange }) {
  const handleToggle = (value) => {
    if (selectedValues.includes(value)) {
      // Remove if already selected
      onChange(selectedValues.filter(item => item !== value));
    } else {
      // Add if not selected
      onChange([...selectedValues, value]);
    }
  };
  
  return (
    <View className="space-y-2">
      {options.map((option) => (
        <Checkbox
          key={option.value}
          checked={selectedValues.includes(option.value)}
          onChange={() => handleToggle(option.value)}
          label={option.label}
        />
      ))}
    </View>
  );
}
 
// Usage example
function FilterOptions() {
  const [selectedFilters, setSelectedFilters] = useState([]);
  
  const filterOptions = [
    { label: 'Price: Low to High', value: 'price_asc' },
    { label: 'Price: High to Low', value: 'price_desc' },
    { label: 'Newest First', value: 'newest' },
    { label: 'Rating', value: 'rating' },
  ];
  
  return (
    <View>
      <Text className="font-bold mb-2">Sort By:</Text>
      <CheckboxList
        options={filterOptions}
        selectedValues={selectedFilters}
        onChange={setSelectedFilters}
      />
    </View>
  );
}

Best Practices

Provide Clear Labels

Use concise, descriptive labels that clearly indicate what the checkbox controls:

// Good: Clear label
<Checkbox
  checked={isSubscribed}
  onChange={setIsSubscribed}
  label="Receive weekly newsletter"
/>
 
// Avoid: Vague label
<Checkbox
  checked={isSubscribed}
  onChange={setIsSubscribed}
  label="Newsletter"
/>

Handle Form Submission Validation

Always validate checkbox state before form submission when required:

function handleSubmit() {
  if (!termsAccepted) {
    setTermsError('You must accept the terms to continue');
    return;
  }
  
  // Proceed with form submission
  submitForm();
}

Visual Feedback for Errors

Provide clear visual feedback when validation fails:

<Checkbox
  checked={termsAccepted}
  onChange={setTermsAccepted}
  label="I agree to the terms and conditions"
  error={!termsAccepted && formSubmitted ? 'This field is required' : ''}
/>

For related checkboxes, maintain values in an array:

function FilterSection() {
  const [selectedCategories, setSelectedCategories] = useState([]);
  
  const toggleCategory = (category, checked) => {
    if (checked) {
      setSelectedCategories([...selectedCategories, category]);
    } else {
      setSelectedCategories(
        selectedCategories.filter(item => item !== category)
      );
    }
  };
  
  return (
    <View>
      <Text className="font-bold mb-2">Categories:</Text>
      
      <Checkbox
        checked={selectedCategories.includes('electronics')}
        onChange={(checked) => toggleCategory('electronics', checked)}
        label="Electronics"
      />
      
      <Checkbox
        checked={selectedCategories.includes('clothing')}
        onChange={(checked) => toggleCategory('clothing', checked)}
        label="Clothing"
      />
      
      <Checkbox
        checked={selectedCategories.includes('books')}
        onChange={(checked) => toggleCategory('books', checked)}
        label="Books"
      />
    </View>
  );
}

Implementation Details

The Checkbox component is built using React Native's Pressable and View components. It renders a square with a border that changes appearance when checked. When checked, it displays a checkmark icon using the Icon component.

The component accepts a label that's displayed next to the checkbox, and an optional error message that appears below the checkbox when provided. The error message is styled in red to draw attention to validation issues.

The onChange callback is triggered whenever the user taps the checkbox, inverting the current checked state. Because this is a controlled component, you must update the checked prop in your parent component when this callback is called.

Notes

  • The Checkbox is a controlled component, so you must handle its state externally
  • Error messages appear below the checkbox when the error prop is provided
  • The component includes appropriate spacing with margin-bottom for layout consistency
  • The checkbox and label are wrapped in a Pressable, allowing users to tap either the box or label
  • For groups of related checkboxes, maintain an array of selected values in your state