component. -->
Demo
A control enabling the user to switch between a checked and unchecked state.
npx @react-native-reusables/cli@latest add switch
Copy/paste the following code to ~/components/ui/switch.tsx:
~/components/ui/switch.tsx
import * as SwitchPrimitives from '@rn-primitives/switch';import * as React from 'react';import { Platform } from 'react-native';import Animated, { interpolateColor, useAnimatedStyle, useDerivedValue, withTiming,} from 'react-native-reanimated';import { useColorScheme } from '~/lib/useColorScheme';import { cn } from '~/lib/utils'; const SwitchWeb = React.forwardRef<SwitchPrimitives.RootRef, SwitchPrimitives.RootProps>( ({ className, ...props }, ref) => ( <SwitchPrimitives.Root className={cn( 'peer flex-row h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed', props.checked ? 'bg-primary' : 'bg-input', props.disabled && 'opacity-50', className )} {...props} ref={ref} > <SwitchPrimitives.Thumb className={cn( 'pointer-events-none block h-5 w-5 rounded-full bg-background shadow-md shadow-foreground/5 ring-0 transition-transform', props.checked ? 'translate-x-5' : 'translate-x-0' )} /> </SwitchPrimitives.Root> )); SwitchWeb.displayName = 'SwitchWeb'; const RGB_COLORS = { light: { primary: 'rgb(24, 24, 27)', input: 'rgb(228, 228, 231)', }, dark: { primary: 'rgb(250, 250, 250)', input: 'rgb(39, 39, 42)', },} as const; const SwitchNative = React.forwardRef<SwitchPrimitives.RootRef, SwitchPrimitives.RootProps>( ({ className, ...props }, ref) => { const { colorScheme } = useColorScheme(); const translateX = useDerivedValue(() => (props.checked ? 18 : 0)); const animatedRootStyle = useAnimatedStyle(() => { return { backgroundColor: interpolateColor( translateX.value, [0, 18], [RGB_COLORS[colorScheme].input, RGB_COLORS[colorScheme].primary] ), }; }); const animatedThumbStyle = useAnimatedStyle(() => ({ transform: [{ translateX: withTiming(translateX.value, { duration: 200 }) }], })); return ( <Animated.View style={animatedRootStyle} className={cn('h-8 w-[46px] rounded-full', props.disabled && 'opacity-50')} > <SwitchPrimitives.Root className={cn( 'flex-row h-8 w-[46px] shrink-0 items-center rounded-full border-2 border-transparent', props.checked ? 'bg-primary' : 'bg-input', className )} {...props} ref={ref} > <Animated.View style={animatedThumbStyle}> <SwitchPrimitives.Thumb className={'h-7 w-7 rounded-full bg-background shadow-md shadow-foreground/25 ring-0'} /> </Animated.View> </SwitchPrimitives.Root> </Animated.View> ); });SwitchNative.displayName = 'SwitchNative'; const Switch = Platform.select({ web: SwitchWeb, default: SwitchNative,}); export { Switch };
import * as React from 'react';import { View } from 'react-native';import { Label } from '~/components/ui/label';import { Switch } from '~/components/ui/switch'; function Example() { const [checked, setChecked] = React.useState(false); return ( <> <View className='flex-1 justify-center items-center p-6 gap-12'> <View className='flex-row items-center gap-2'> <Switch checked={checked} onCheckedChange={setChecked} nativeID='airplane-mode' /> <Label nativeID='airplane-mode' onPress={() => { setChecked((prev) => !prev); }} > Airplane Mode </Label> </View> </View> </> );}
Extends Pressable props
Pressable