Slider Primitive
An input allowing the user to choose a value from a specified range.
Installation
Install the component via your command line.
npx expo install @rn-primitives/slider
Install @radix-ui/react-slider
npx expo install @radix-ui/react-slider
Copy/paste the following code for web to ~/components/primitives/slider/slider.web.tsx
import * as Slider from '@radix-ui/react-slider';import * as Slot from '~/components/primitives/slot';import * as React from 'react';import { View } from 'react-native';import type { RangeProps, RangeRef, RootProps, RootRef, ThumbProps, ThumbRef, TrackProps, TrackRef,} from './types';
const Root = React.forwardRef<RootRef, RootProps>( ( { asChild, value, disabled, min, max, dir, inverted, step = 1, onValueChange, ...props }, ref ) => { const Component = asChild ? Slot.View : View; return ( <Slider.Root dir={dir} inverted={inverted} value={[value]} disabled={disabled} min={min} max={max} step={step} onValueChange={onValueChange} asChild > <Component ref={ref} {...props} /> </Slider.Root> ); });
Root.displayName = 'RootWebSlider';
const Track = React.forwardRef<TrackRef, TrackProps>(({ asChild, ...props }, ref) => { const Component = asChild ? Slot.View : View; return ( <Slider.Track asChild> <Component ref={ref} {...props} /> </Slider.Track> );});
Track.displayName = 'TrackWebSlider';
const Range = React.forwardRef<RangeRef, RangeProps>(({ asChild, ...props }, ref) => { const Component = asChild ? Slot.View : View; return ( <Slider.Range asChild> <Component ref={ref} {...props} /> </Slider.Range> );});
Range.displayName = 'RangeWebSlider';
const Thumb = React.forwardRef<ThumbRef, ThumbProps>(({ asChild, ...props }, ref) => { const Component = asChild ? Slot.View : View; return ( <Slider.Thumb asChild> <Component ref={ref} {...props} /> </Slider.Thumb> );});
Thumb.displayName = 'ThumbWebSlider';
export { Range, Root, Thumb, Track };
Copy/paste the following code for native to ~/components/primitives/slider/slider.tsx
import * as Slot from '~/components/primitives/slot';import * as React from 'react';import { View } from 'react-native';import type { RangeProps, RangeRef, RootProps, RootRef, ThumbProps, ThumbRef, TrackProps, TrackRef,} from './types';
const RootContext = React.createContext<RootProps | null>(null);
const Root = React.forwardRef<RootRef, RootProps>( ( { asChild, value, disabled, min, max, dir: _dir, inverted: _inverted, step: _step, onValueChange: _onValueChange, ...props }, ref ) => { const Component = asChild ? Slot.View : View; return ( <RootContext.Provider value={{ value, disabled, min, max }}> <Component ref={ref} role='group' {...props} /> </RootContext.Provider> ); });
Root.displayName = 'RootNativeSlider';
function useSliderContext() { const context = React.useContext(RootContext); if (context === null) { throw new Error('Slider compound components cannot be rendered outside the Slider component'); } return context;}
const Track = React.forwardRef<TrackRef, TrackProps>(({ asChild, ...props }, ref) => { const { value, min, max, disabled } = useSliderContext();
const Component = asChild ? Slot.View : View; return ( <Component ref={ref} aria-disabled={disabled} role='slider' aria-valuemin={min} aria-valuemax={max} aria-valuenow={value} accessibilityValue={{ max, min, now: value }} {...props} /> );});
Track.displayName = 'TrackNativeSlider';
const Range = React.forwardRef<RangeRef, RangeProps>(({ asChild, ...props }, ref) => { const Component = asChild ? Slot.View : View; return <Component ref={ref} role='presentation' {...props} />;});
Range.displayName = 'RangeNativeSlider';
const Thumb = React.forwardRef<ThumbRef, ThumbProps>(({ asChild, ...props }, ref) => { const Component = asChild ? Slot.View : View; return <Component accessibilityRole='adjustable' ref={ref} {...props} />;});
Thumb.displayName = 'ThumbNativeSlider';
export { Range, Root, Thumb, Track };
Copy/paste the following code for types to ~/components/primitives/slider/types.ts
import type { SlottableViewProps, ViewRef } from '~/components/primitives/types';
type RootProps = SlottableViewProps & { value: number; disabled?: boolean; min?: number; max?: number; /** * Platform: WEB ONLY */ dir?: 'ltr' | 'rtl'; /** * Platform: WEB ONLY */ inverted?: boolean; /** * Platform: WEB ONLY */ step?: number; /** * Platform: WEB ONLY */ onValueChange?: (value: number[]) => void;};
type TrackProps = SlottableViewProps;type RangeProps = SlottableViewProps;type ThumbProps = SlottableViewProps;
type RootRef = ViewRef;type TrackRef = ViewRef;type RangeRef = ViewRef;type ThumbRef = ViewRef;
export type { RangeProps, RangeRef, RootProps, RootRef, ThumbProps, ThumbRef, TrackProps, TrackRef,};
Copy/paste the following code for exporting to ~/components/primitives/slider/index.ts
export * from './slider';export * from './types';
Copy/paste the following code for native to ~/components/primitives/slider/index.tsx
import * as Slot from '~/components/primitives/slot';import * as React from 'react';import { View } from 'react-native';import type { RangeProps, RangeRef, RootProps, RootRef, ThumbProps, ThumbRef, TrackProps, TrackRef,} from './types';
const RootContext = React.createContext<RootProps | null>(null);
const Root = React.forwardRef<RootRef, RootProps>( ( { asChild, value, disabled, min, max, dir: _dir, inverted: _inverted, step: _step, onValueChange: _onValueChange, ...props }, ref ) => { const Component = asChild ? Slot.View : View; return ( <RootContext.Provider value={{ value, disabled, min, max }}> <Component ref={ref} role='group' {...props} /> </RootContext.Provider> ); });
Root.displayName = 'RootNativeSlider';
function useSliderContext() { const context = React.useContext(RootContext); if (context === null) { throw new Error('Slider compound components cannot be rendered outside the Slider component'); } return context;}
const Track = React.forwardRef<TrackRef, TrackProps>(({ asChild, ...props }, ref) => { const { value, min, max, disabled } = useSliderContext();
const Component = asChild ? Slot.View : View; return ( <Component ref={ref} aria-disabled={disabled} role='slider' aria-valuemin={min} aria-valuemax={max} aria-valuenow={value} accessibilityValue={{ max, min, now: value }} {...props} /> );});
Track.displayName = 'TrackNativeSlider';
const Range = React.forwardRef<RangeRef, RangeProps>(({ asChild, ...props }, ref) => { const Component = asChild ? Slot.View : View; return <Component ref={ref} role='presentation' {...props} />;});
Range.displayName = 'RangeNativeSlider';
const Thumb = React.forwardRef<ThumbRef, ThumbProps>(({ asChild, ...props }, ref) => { const Component = asChild ? Slot.View : View; return <Component accessibilityRole='adjustable' ref={ref} {...props} />;});
Thumb.displayName = 'ThumbNativeSlider';
export { Range, Root, Thumb, Track };
Copy/paste the following code for types to ~/components/primitives/slider/types.ts
import type { SlottableViewProps, ViewRef } from '~/components/primitives/types';
type RootProps = SlottableViewProps & { value: number; disabled?: boolean; min?: number; max?: number; /** * Platform: WEB ONLY */ dir?: 'ltr' | 'rtl'; /** * Platform: WEB ONLY */ inverted?: boolean; /** * Platform: WEB ONLY */ step?: number; /** * Platform: WEB ONLY */ onValueChange?: (value: number[]) => void;};
type TrackProps = SlottableViewProps;type RangeProps = SlottableViewProps;type ThumbProps = SlottableViewProps;
type RootRef = ViewRef;type TrackRef = ViewRef;type RangeRef = ViewRef;type ThumbRef = ViewRef;
export type { RangeProps, RangeRef, RootProps, RootRef, ThumbProps, ThumbRef, TrackProps, TrackRef,};
Usage
import * as React from 'react';import { View, Text, Platform } from 'react-native';import * as SelectPrimitive from '@rn-primitives/select';
function Example() { const [value, setValue] = React.useState(50);
return ( <View > <Text>{Math.round(value)}</Text> <Slider.Root value={value} onValueChange={(vals) => { const nextValue = vals[0]; if (typeof nextValue !== 'number') return; setValue(nextValue); }} > <Slider.Track> <Slider.Range style={{ width: `${value}%` }} /> <Slider.Thumb style={{ left: `${value}%` }} /> </Slider.Track> </Slider.Root>
{Platform.OS !== 'web' && ( <Text> You will have to implement the gesture handling </Text> )} </View> );}
Props
Root
Extends View
props
Prop | Type | Note |
---|---|---|
value | number | (optional) |
disabled | boolean | (optional) |
min | number | (optional) |
max | number | (optional) |
dir | ’ltr’ | ‘rtl’ | Web Only (optional) |
inverted | boolean | Web Only (optional) |
step | number | Web Only (optional) |
onValueChange | (value: string[] ) => void | Web Only (optional) |
Track
Extends View
props
Prop | Type | Note |
---|---|---|
asChild | boolean | (optional) |
Range
Extends View
props
Prop | Type | Note |
---|---|---|
asChild | boolean | (optional) |
Thumb
Extends View
props
Prop | Type | Note |
---|---|---|
asChild | boolean | (optional) |