AniUI

Slider

An interactive slider component for selecting a value within a range.

import { Slider } from "@/components/ui/slider";
import { useState } from "react";

export function MyScreen() {
  const [value, setValue] = useState(50);
  return (
    <Slider
      value={value}
      onValueChange={setValue}
      min={0}
      max={100}
    />
  );
}

Installation

npx @aniui/cli add slider

Usage

app/index.tsx
import { Slider } from "@/components/ui/slider";
import { useState } from "react";

export function MyScreen() {
  const [value, setValue] = useState(50);
  return (
    <Slider
      value={value}
      onValueChange={setValue}
      min={0}
      max={100}
    />
  );
}

Default

import { Slider } from "@/components/ui/slider";
import { useState } from "react";

export function MyScreen() {
  const [value, setValue] = useState(50);
  return (
    <Slider
      value={value}
      onValueChange={setValue}
      min={0}
      max={100}
    />
  );
}

Disabled

<Slider value={30} disabled />

Props

PropTypeDefault
value
number
0
min
number
0
max
number
100
step
number
1
size
"sm" | "md" | "lg"
"md"
disabled
boolean
false
onValueChange
(value: number) => void
className
string

Also accepts all View props from React Native.

Source

components/ui/slider.tsx
import React, { useState } from "react";
import { View, Pressable } from "react-native";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";

const sliderVariants = cva("w-full justify-center", {
  variants: {
    size: {
      sm: "h-8",
      md: "h-10",
      lg: "h-12",
    },
  },
  defaultVariants: { size: "md" },
});
export interface SliderProps
  extends React.ComponentPropsWithoutRef<typeof View>,
    VariantProps<typeof sliderVariants> {
  className?: string;
  value?: number;
  min?: number;
  max?: number;
  step?: number;
  disabled?: boolean;
  onValueChange?: (value: number) => void;
}
export function Slider({
  value = 0, min = 0, max = 100, step = 1, disabled, size,
  onValueChange, className, ...props
}: SliderProps) {
  const [width, setWidth] = useState(0);
  const pct = Math.max(0, Math.min(100, ((value - min) / (max - min)) * 100));
  const handlePress = (e: { nativeEvent: { locationX: number } }) => {
    if (disabled) return;
    const raw = min + ((e.nativeEvent.locationX / width) * (max - min));
    const stepped = Math.round(raw / step) * step;
    onValueChange?.(Math.max(min, Math.min(max, stepped)));
  };
  return (
    <Pressable
      className={cn(sliderVariants({ size }), disabled && "opacity-50", className)}
      onLayout={(e) => setWidth(e.nativeEvent.layout.width)}
      onPress={handlePress}
      accessible={true}
      accessibilityRole="adjustable"
      accessibilityValue={{ min, max, now: value }}
      disabled={disabled}
      {...props}
    >
      <View className="h-1.5 w-full rounded-full bg-secondary">
        <View className="h-full rounded-full bg-primary" style={{ width: `${pct}%` }} />
      </View>
      <View
        className="absolute h-5 w-5 rounded-full border-2 border-primary bg-background"
        style={{ left: `${pct}%`, marginLeft: -10 }}
      />
    </Pressable>
  );
}