Switch Primitive
A control enabling the user to switch between a checked and unchecked state.
Installation
Install the component via your command line.
npx expo install @rn-primitives/switch
Install @radix-ui/react-switch
npx expo install @radix-ui/react-switch
Copy/paste the following code for web to ~/components/primitives/switch/switch.web.tsx
import * as Switch from '@radix-ui/react-switch';import * as Slot from '~/components/primitives/slot';import * as React from 'react';import { Pressable, View, type GestureResponderEvent } from 'react-native';import type { RootProps, RootRef, ThumbProps, ThumbRef } from './types';
const Root = React.forwardRef<RootRef, RootProps>( ( { asChild, checked, onCheckedChange, disabled, onPress: onPressProp, onKeyDown: onKeyDownProp, ...props }, ref ) => { function onPress(ev: GestureResponderEvent) { onCheckedChange(!checked); onPressProp?.(ev); }
function onKeyDown(ev: React.KeyboardEvent) { onKeyDownProp?.(ev); if (ev.key === ' ') { onCheckedChange(!checked); } }
const Component = asChild ? Slot.Pressable : Pressable; return ( <Switch.Root checked={checked} onCheckedChange={onCheckedChange} disabled={disabled} asChild> <Component ref={ref} disabled={disabled} onPress={onPress} // @ts-expect-error Web only onKeyDown={onKeyDown} {...props} /> </Switch.Root> ); });
Root.displayName = 'RootWebSwitch';
const Thumb = React.forwardRef<ThumbRef, ThumbProps>(({ asChild, ...props }, ref) => { const Component = asChild ? Slot.View : View; return ( <Switch.Thumb asChild> <Component ref={ref} {...props} /> </Switch.Thumb> );});
Thumb.displayName = 'ThumbWebSwitch';
export { Root, Thumb };
Copy/paste the following code for native to ~/components/primitives/switch/switch.tsx
import * as Slot from '~/components/primitives/slot';import * as React from 'react';import { Pressable, View, type GestureResponderEvent } from 'react-native';import type { RootProps, RootRef, ThumbProps, ThumbRef } from './types';
const Root = React.forwardRef<RootRef, RootProps>( ( { asChild, checked, onCheckedChange, disabled, onPress: onPressProp, 'aria-valuetext': ariaValueText, ...props }, ref ) => { function onPress(ev: GestureResponderEvent) { if (disabled) return; onCheckedChange(!checked); onPressProp?.(ev); }
const Component = asChild ? Slot.Pressable : Pressable; return ( <Component ref={ref} aria-disabled={disabled} role='switch' aria-checked={checked} aria-valuetext={ariaValueText ?? checked ? 'on' : 'off'} onPress={onPress} accessibilityState={{ checked, disabled, }} disabled={disabled} {...props} /> ); });
Root.displayName = 'RootNativeSwitch';
const Thumb = React.forwardRef<ThumbRef, ThumbProps>(({ asChild, ...props }, ref) => { const Component = asChild ? Slot.View : View; return <Component ref={ref} role='presentation' {...props} />;});
Thumb.displayName = 'ThumbNativeSwitch';
export { Root, Thumb };
Copy/paste the following code for types to ~/components/primitives/switch/types.ts
import type { PressableRef, SlottablePressableProps, SlottableViewProps, ViewRef,} from '~/components/primitives/types';
type RootProps = SlottablePressableProps & { checked: boolean; onCheckedChange: (checked: boolean) => void; disabled?: boolean; /** * Platform: WEB ONLY */ onKeyDown?: (ev: React.KeyboardEvent) => void;};
type ThumbProps = SlottableViewProps;
type RootRef = PressableRef;type ThumbRef = ViewRef;
export type { RootProps, RootRef, ThumbProps, ThumbRef };
Copy/paste the following code for exporting to ~/components/primitives/switch/index.ts
export * from './switch';export * from './types';
Copy/paste the following code for native to ~/components/primitives/switch/index.tsx
import * as Slot from '~/components/primitives/slot';import * as React from 'react';import { Pressable, View, type GestureResponderEvent } from 'react-native';import type { RootProps, RootRef, ThumbProps, ThumbRef } from './types';
const Root = React.forwardRef<RootRef, RootProps>( ( { asChild, checked, onCheckedChange, disabled, onPress: onPressProp, 'aria-valuetext': ariaValueText, ...props }, ref ) => { function onPress(ev: GestureResponderEvent) { if (disabled) return; onCheckedChange(!checked); onPressProp?.(ev); }
const Component = asChild ? Slot.Pressable : Pressable; return ( <Component ref={ref} aria-disabled={disabled} role='switch' aria-checked={checked} aria-valuetext={ariaValueText ?? checked ? 'on' : 'off'} onPress={onPress} accessibilityState={{ checked, disabled, }} disabled={disabled} {...props} /> ); });
Root.displayName = 'RootNativeSwitch';
const Thumb = React.forwardRef<ThumbRef, ThumbProps>(({ asChild, ...props }, ref) => { const Component = asChild ? Slot.View : View; return <Component ref={ref} role='presentation' {...props} />;});
Thumb.displayName = 'ThumbNativeSwitch';
export { Root, Thumb };
Copy/paste the following code for types to ~/components/primitives/switch/types.ts
import type { PressableRef, SlottablePressableProps, SlottableViewProps, ViewRef,} from '~/components/primitives/types';
type RootProps = SlottablePressableProps & { checked: boolean; onCheckedChange: (checked: boolean) => void; disabled?: boolean; /** * Platform: WEB ONLY */ onKeyDown?: (ev: React.KeyboardEvent) => void;};
type ThumbProps = SlottableViewProps;
type RootRef = PressableRef;type ThumbRef = ViewRef;
export type { RootProps, RootRef, ThumbProps, ThumbRef };
Usage
import * as React from 'react';import * as SwitchPrimitive from '@rn-primitives/switch';
export default function SwitchScreen() { const [checked, setChecked] = React.useState(false);
return ( <SwitchPrimitive.Root checked={checked} onCheckedChange={setChecked}> <SwitchPrimitive.Thumb /> </SwitchPrimitive.Root> );}
Props
Root
Extends Pressable
props
Prop | Type | Note |
---|---|---|
checked | boolean | |
onCheckedChange | (checked: boolean) => void | |
disabled | boolean | (optional) |
asChild | boolean | (optional) |
onKeyDown | (ev: React.KeyboardEvent) => void | Web Only (optional) |
Thumb
Extends View
props
Prop | Type | Note |
---|---|---|
asChild | boolean | (optional) |