packages/codemod/docs/RANGE_SLIDER_MIGRATION.md
This document outlines the migration from Chakra UI v2 RangeSlider component to v3 Slider (range mode).
import {
RangeSlider,
RangeSliderFilledTrack,
RangeSliderThumb,
RangeSliderTrack,
} from "@chakra-ui/react"
;<RangeSlider aria-label={["min", "max"]} defaultValue={[10, 30]}>
<RangeSliderTrack>
<RangeSliderFilledTrack />
</RangeSliderTrack>
<RangeSliderThumb index={0} />
<RangeSliderThumb index={1} />
</RangeSlider>
import { Slider } from "@chakra-ui/react"
;<Slider.Root aria-label={["min", "max"]} defaultValue={[10, 30]}>
<Slider.Control>
<Slider.Track>
<Slider.Range />
</Slider.Track>
<Slider.Thumb index={0}>
<Slider.HiddenInput />
</Slider.Thumb>
<Slider.Thumb index={1}>
<Slider.HiddenInput />
</Slider.Thumb>
</Slider.Control>
</Slider.Root>
Component Naming:
RangeSlider → Slider.Root (unified with regular Slider)RangeSliderTrack → Slider.TrackRangeSliderFilledTrack → Slider.RangeRangeSliderThumb → Slider.ThumbNew Required Elements:
<Slider.Control> - Must wrap Track and Thumbs<Slider.HiddenInput /> - Must be first child of each ThumbImport Changes:
Slider instead of RangeSlider components| v2 Prop | v3 Prop | Notes |
|---|---|---|
colorScheme | colorPalette | Renamed for consistency |
onChange | onValueChange | Receives object: { value, valueAsString } |
onChangeEnd | onValueChangeEnd | Receives object: { value, valueAsString } |
value | value | Now array: [min, max] |
defaultValue | defaultValue | Now array: [min, max] |
min | min | No change |
max | max | No change |
step | step | No change |
orientation | orientation | No change |
isDisabled | disabled | Standard HTML attribute (note: v3 uses isDisabled, no change needed) |
| v2 Prop | v3 Equivalent | Notes |
|---|---|---|
focusThumbOnChange | (removed) | No longer supported in v3 |
reversed | (removed) | Use dir='rtl' for RTL direction |
v2:
import {
RangeSlider,
RangeSliderFilledTrack,
RangeSliderThumb,
RangeSliderTrack,
} from "@chakra-ui/react"
function App() {
return (
<RangeSlider aria-label={["min", "max"]} defaultValue={[10, 30]}>
<RangeSliderTrack>
<RangeSliderFilledTrack />
</RangeSliderTrack>
<RangeSliderThumb index={0} />
<RangeSliderThumb index={1} />
</RangeSlider>
)
}
v3:
import { Slider } from "@chakra-ui/react"
function App() {
return (
<Slider.Root aria-label={["min", "max"]} defaultValue={[10, 30]}>
<Slider.Control>
<Slider.Track>
<Slider.Range />
</Slider.Track>
<Slider.Thumb index={0}>
<Slider.HiddenInput />
</Slider.Thumb>
<Slider.Thumb index={1}>
<Slider.HiddenInput />
</Slider.Thumb>
</Slider.Control>
</Slider.Root>
)
}
v2:
import {
RangeSlider,
RangeSliderFilledTrack,
RangeSliderThumb,
RangeSliderTrack,
} from "@chakra-ui/react"
function App() {
return (
<RangeSlider
aria-label={["min", "max"]}
colorScheme="pink"
defaultValue={[10, 30]}
>
<RangeSliderTrack>
<RangeSliderFilledTrack />
</RangeSliderTrack>
<RangeSliderThumb index={0} />
<RangeSliderThumb index={1} />
</RangeSlider>
)
}
v3:
import { Slider } from "@chakra-ui/react"
function App() {
return (
<Slider.Root
aria-label={["min", "max"]}
colorPalette="pink"
defaultValue={[10, 30]}
>
<Slider.Control>
<Slider.Track>
<Slider.Range />
</Slider.Track>
<Slider.Thumb index={0}>
<Slider.HiddenInput />
</Slider.Thumb>
<Slider.Thumb index={1}>
<Slider.HiddenInput />
</Slider.Thumb>
</Slider.Control>
</Slider.Root>
)
}
v2:
import {
RangeSlider,
RangeSliderFilledTrack,
RangeSliderThumb,
RangeSliderTrack,
} from "@chakra-ui/react"
function App() {
return (
<RangeSlider
aria-label={["min", "max"]}
colorScheme="pink"
defaultValue={[10, 30]}
orientation="vertical"
minH="32"
>
<RangeSliderTrack>
<RangeSliderFilledTrack />
</RangeSliderTrack>
<RangeSliderThumb index={0} />
<RangeSliderThumb index={1} />
</RangeSlider>
)
}
v3:
import { Slider } from "@chakra-ui/react"
function App() {
return (
<Slider.Root
aria-label={["min", "max"]}
colorPalette="pink"
defaultValue={[10, 30]}
orientation="vertical"
minH="32"
>
<Slider.Control>
<Slider.Track>
<Slider.Range />
</Slider.Track>
<Slider.Thumb index={0}>
<Slider.HiddenInput />
</Slider.Thumb>
<Slider.Thumb index={1}>
<Slider.HiddenInput />
</Slider.Thumb>
</Slider.Control>
</Slider.Root>
)
}
v2:
import {
Box,
RangeSlider,
RangeSliderFilledTrack,
RangeSliderThumb,
RangeSliderTrack,
} from "@chakra-ui/react"
import { MdGraphicEq } from "react-icons/md"
function App() {
return (
<RangeSlider aria-label={["min", "max"]} defaultValue={[30, 80]}>
<RangeSliderTrack bg="red.100">
<RangeSliderFilledTrack bg="tomato" />
</RangeSliderTrack>
<RangeSliderThumb boxSize={6} index={0}>
<Box color="tomato" as={MdGraphicEq} />
</RangeSliderThumb>
<RangeSliderThumb boxSize={6} index={1}>
<Box color="tomato" as={MdGraphicEq} />
</RangeSliderThumb>
</RangeSlider>
)
}
v3:
import { Box, Slider } from "@chakra-ui/react"
import { MdGraphicEq } from "react-icons/md"
function App() {
return (
<Slider.Root aria-label={["min", "max"]} defaultValue={[30, 80]}>
<Slider.Control>
<Slider.Track bg="red.100">
<Slider.Range bg="tomato" />
</Slider.Track>
<Slider.Thumb boxSize={6} index={0}>
<Slider.HiddenInput />
<Box color="tomato" as={MdGraphicEq} />
</Slider.Thumb>
<Slider.Thumb boxSize={6} index={1}>
<Slider.HiddenInput />
<Box color="tomato" as={MdGraphicEq} />
</Slider.Thumb>
</Slider.Control>
</Slider.Root>
)
}
v2:
import {
RangeSlider,
RangeSliderFilledTrack,
RangeSliderThumb,
RangeSliderTrack,
} from "@chakra-ui/react"
function App() {
return (
<RangeSlider defaultValue={[120, 240]} min={0} max={300} step={30}>
<RangeSliderTrack bg="red.100">
<RangeSliderFilledTrack bg="tomato" />
</RangeSliderTrack>
<RangeSliderThumb boxSize={6} index={0} />
<RangeSliderThumb boxSize={6} index={1} />
</RangeSlider>
)
}
v3:
import { Slider } from "@chakra-ui/react"
function App() {
return (
<Slider.Root defaultValue={[120, 240]} min={0} max={300} step={30}>
<Slider.Control>
<Slider.Track bg="red.100">
<Slider.Range bg="tomato" />
</Slider.Track>
<Slider.Thumb boxSize={6} index={0}>
<Slider.HiddenInput />
</Slider.Thumb>
<Slider.Thumb boxSize={6} index={1}>
<Slider.HiddenInput />
</Slider.Thumb>
</Slider.Control>
</Slider.Root>
)
}
v2:
import {
RangeSlider,
RangeSliderFilledTrack,
RangeSliderThumb,
RangeSliderTrack,
} from "@chakra-ui/react"
import { useState } from "react"
function App() {
const [value, setValue] = useState([20, 60])
return (
<RangeSlider value={value} onChange={setValue} min={0} max={100}>
<RangeSliderTrack>
<RangeSliderFilledTrack />
</RangeSliderTrack>
<RangeSliderThumb index={0} />
<RangeSliderThumb index={1} />
</RangeSlider>
)
}
v3:
import { Slider } from "@chakra-ui/react"
import { useState } from "react"
function App() {
const [value, setValue] = useState([20, 60])
return (
<Slider.Root
value={value}
onValueChange={(e) => setValue(e.value)}
min={0}
max={100}
>
<Slider.Control>
<Slider.Track>
<Slider.Range />
</Slider.Track>
<Slider.Thumb index={0}>
<Slider.HiddenInput />
</Slider.Thumb>
<Slider.Thumb index={1}>
<Slider.HiddenInput />
</Slider.Thumb>
</Slider.Control>
</Slider.Root>
)
}
v2:
import {
RangeSlider,
RangeSliderFilledTrack,
RangeSliderThumb,
RangeSliderTrack,
} from "@chakra-ui/react"
function App() {
return (
<RangeSlider
aria-label={["min", "max"]}
onChange={(val) => console.log("changing", val)}
onChangeEnd={(val) => console.log("done", val)}
>
<RangeSliderTrack>
<RangeSliderFilledTrack />
</RangeSliderTrack>
<RangeSliderThumb index={0} />
<RangeSliderThumb index={1} />
</RangeSlider>
)
}
v3:
import { Slider } from "@chakra-ui/react"
function App() {
return (
<Slider.Root
aria-label={["min", "max"]}
onValueChange={(e) => console.log("changing", e.value)}
onValueChangeEnd={(e) => console.log("done", e.value)}
>
<Slider.Control>
<Slider.Track>
<Slider.Range />
</Slider.Track>
<Slider.Thumb index={0}>
<Slider.HiddenInput />
</Slider.Thumb>
<Slider.Thumb index={1}>
<Slider.HiddenInput />
</Slider.Thumb>
</Slider.Control>
</Slider.Root>
)
}
To automatically migrate your RangeSlider components, run:
npx @chakra-ui/codemod transform range-slider <path>
--dry - Do a dry-run without making changes--print - Print the changed output for comparison# Transform all files in src directory
npx @chakra-ui/codemod transform range-slider ./src
# Dry run to preview changes
npx @chakra-ui/codemod transform range-slider ./src --dry
# Print changes for comparison
npx @chakra-ui/codemod transform range-slider ./src --print
If you prefer to migrate manually:
Update Imports:
RangeSlider components to SliderUpdate Component Names:
<RangeSlider> → <Slider.Root><RangeSliderTrack> → <Slider.Track><RangeSliderFilledTrack> → <Slider.Range><RangeSliderThumb> → <Slider.Thumb>Add Required Elements:
<Slider.Control><Slider.HiddenInput /> as first child of each ThumbUpdate Props:
colorScheme → colorPaletteonChange → onValueChange (receives { value, valueAsString } object)onChangeEnd → onValueChangeEnd (receives { value, valueAsString }
object)focusThumbOnChangereversed (use dir='rtl' if needed)RangeSlider* → Slider.* (namespace component)colorScheme → colorPaletteonChange → onValueChangeonChangeEnd → onValueChangeEndfocusThumbOnChange - no longer supportedreversed - use dir='rtl' for RTL layoutsonChange(value) → onValueChange({ value, valueAsString })onChangeEnd(value) → onValueChangeEnd({ value, valueAsString })value (array) and valueAsString (joined
string)useRangeSlider() → useSlider() (unified hook from @ark-ui/react)The codemod will:
<RangeSlider> to <Slider.Root> with proper structure<Slider.Control> wrapper around Track and Thumbs<Slider.HiddenInput /> to each ThumbcolorScheme to colorPaletteonChange to onValueChangeonChangeEnd to onValueChangeEndfocusThumbOnChange propreversed propThe v3 Slider (RangeSlider) component provides:
Slider component for both single-value and
range sliders
<Slider.Root value={50}> with one Thumb<Slider.Root value={[10, 30]}> with multiple Thumbs{ value, valueAsString } instead of just
the value:
onChange={(value) => setValue(value)}onValueChange={(e) => setValue(e.value)}<Slider.Thumb> requires <Slider.HiddenInput /> as first child for
proper form integration<Slider.Control> is required to wrap Track and Thumbsindex prop on Thumbs is preserved and required for proper range slider
functionality