Slider
A control element that allows for a range of selections.
import { defineConfig } from '@pandacss/dev'
import { createPreset } from '@park-ui/panda-preset'
export default defineConfig({
preflight: true,
presets: [
'@pandacss/preset-base',
createPreset({
accentColor: '__ACCENT_COLOR__',
grayColor: '__GRAY_COLOR__',
borderRadius: '__BORDER_RADIUS__',
}),
],
include: ['./src/**/*.{js,jsx,ts,tsx}'],
jsxFramework: '__JS_FRAMEWORK__',
outdir: 'styled-system',
})
import { parkwindPlugin } from '@park-ui/tailwind-plugin'
import type { Config } from 'tailwindcss'
const config: Config = {
content: ['./src/**/*.{astro,html,js,jsx,svelte,ts,tsx,vue}'],
theme: {
extend: {},
},
plugins: [parkwindPlugin],
parkUI: {
accentColor: '__ACCENT_COLOR__',
grayColor: '__GRAY_COLOR__',
borderRadius: '__BORDER_RADIUS__',
},
darkMode: ['class'],
}
export default config
A control element that allows for a range of selections.
import { Slider, type SliderProps } from '~/components/ui/slider'
export const Demo = (props: SliderProps) => {
return (
<Slider
value={[33]}
marks={[
{ value: 25, label: '25' },
{ value: 50, label: '50' },
{ value: 75, label: '75' },
]}
{...props}
/>
)
}
To use the slider as a range slider, you need to provide an array of values.
<Slider value={[33, 66]}>Label</Slider>
<Slider value={[33, 66]}>Label</Slider>
<Slider value={[33, 66]}>Label</Slider>
The slider can also be used without a label while still showing indicators within the track.
<Slider value={[33]} marks={[{ value: 0 }, { value: 25 }, { value: 50 }, { value: 75 }, { value: 100 }]} />
<Slider value={[33]} marks={[{ value: 0 }, { value: 25 }, { value: 50 }, { value: 75 }, { value: 100 }]} />
<Slider value={[33]} marks={[{ value: 0 }, { value: 25 }, { value: 50 }, { value: 75 }, { value: 100 }]} />
Insert code snippet into your project. Update import paths as needed.
import { Slider as ArkSlider, type SliderRootProps } from '@ark-ui/react/slider'
import { forwardRef, type ReactNode } from 'react'
import { tv, type VariantProps } from 'tailwind-variants'
export interface SliderProps extends SliderRootProps, SliderVariantProps {
children?: ReactNode
marks?: {
value: number
label?: ReactNode
}[]
}
export const Slider = forwardRef<HTMLDivElement, SliderProps>((props, ref) => {
const { children, className, size, ...rootProps } = props
const { root, label, control, track, range, thumb, marker, markerGroup } = styles({ size })
return (
<ArkSlider.Root ref={ref} className={root({ className })} {...rootProps}>
{(api) => (
<>
{children && <ArkSlider.Label className={label()}>{children}</ArkSlider.Label>}
<ArkSlider.Control className={control()}>
<ArkSlider.Track className={track()}>
<ArkSlider.Range className={range()} />
</ArkSlider.Track>
{api.value.map((_, index) => (
<ArkSlider.Thumb key={index} index={index} className={thumb()} />
))}
</ArkSlider.Control>
{props.marks && (
<ArkSlider.MarkerGroup className={markerGroup()}>
{props.marks.map((mark) => (
<ArkSlider.Marker key={mark.value} value={mark.value} className={marker()}>
{mark.label}
</ArkSlider.Marker>
))}
</ArkSlider.MarkerGroup>
)}
</>
)}
</ArkSlider.Root>
)
})
Slider.displayName = 'Slider'
type SliderVariantProps = VariantProps<typeof styles>
const styles = tv(
{
base: 'slider',
defaultVariants: { size: 'md' },
slots: {
root: 'slider__root',
label: 'slider__label',
thumb: 'slider__thumb',
valueText: 'slider__valueText',
track: 'slider__track',
range: 'slider__range',
control: 'slider__control',
markerGroup: 'slider__markerGroup',
marker: 'slider__marker',
},
variants: {
size: {
sm: {
root: 'slider__root--size_sm',
label: 'slider__label--size_sm',
thumb: 'slider__thumb--size_sm',
valueText: 'slider__valueText--size_sm',
track: 'slider__track--size_sm',
range: 'slider__range--size_sm',
control: 'slider__control--size_sm',
markerGroup: 'slider__markerGroup--size_sm',
marker: 'slider__marker--size_sm',
},
md: {
root: 'slider__root--size_md',
label: 'slider__label--size_md',
thumb: 'slider__thumb--size_md',
valueText: 'slider__valueText--size_md',
track: 'slider__track--size_md',
range: 'slider__range--size_md',
control: 'slider__control--size_md',
markerGroup: 'slider__markerGroup--size_md',
marker: 'slider__marker--size_md',
},
lg: {
root: 'slider__root--size_lg',
label: 'slider__label--size_lg',
thumb: 'slider__thumb--size_lg',
valueText: 'slider__valueText--size_lg',
track: 'slider__track--size_lg',
range: 'slider__range--size_lg',
control: 'slider__control--size_lg',
markerGroup: 'slider__markerGroup--size_lg',
marker: 'slider__marker--size_lg',
},
},
},
},
{ twMerge: false },
)
import { Slider as ArkSlider, type SliderRootProps } from '@ark-ui/solid'
import { Index, type JSX, Show, children, splitProps } from 'solid-js'
import { type VariantProps, tv } from 'tailwind-variants'
export interface SliderProps extends SliderRootProps, SliderVariantProps {
children?: JSX.Element
marks?: {
value: number
label?: JSX.Element
}[]
}
export const Slider = (props: SliderProps) => {
const [variantProps, sliderProps] = splitProps(props, ['size', 'class'])
const [localProps, rootProps] = splitProps(sliderProps, ['marks', 'children'])
const getChildren = children(() => localProps.children)
const { root, control, label, marker, markerGroup, range, thumb, track } = styles(variantProps)
return (
<ArkSlider.Root class={root()} {...rootProps}>
{(api) => (
<>
<Show when={getChildren()}>
<ArkSlider.Label class={label()}>{getChildren()}</ArkSlider.Label>
</Show>
<ArkSlider.Control class={control()}>
<ArkSlider.Track class={track()}>
<ArkSlider.Range class={range()} />
</ArkSlider.Track>
<Index each={api().value}>
{(_, index) => <ArkSlider.Thumb index={index} class={thumb()} />}
</Index>
</ArkSlider.Control>
<Show when={localProps.marks}>
<ArkSlider.MarkerGroup class={markerGroup()}>
<Index each={localProps.marks}>
{(mark) => (
<ArkSlider.Marker value={mark().value} class={marker()}>
{mark().label}
</ArkSlider.Marker>
)}
</Index>
</ArkSlider.MarkerGroup>
</Show>
</>
)}
</ArkSlider.Root>
)
}
type SliderVariantProps = VariantProps<typeof styles>
const styles = tv(
{
base: 'slider',
defaultVariants: { size: 'md' },
slots: {
root: 'slider__root',
label: 'slider__label',
thumb: 'slider__thumb',
valueText: 'slider__valueText',
track: 'slider__track',
range: 'slider__range',
control: 'slider__control',
markerGroup: 'slider__markerGroup',
marker: 'slider__marker',
},
variants: {
size: {
sm: {
root: 'slider__root--size_sm',
label: 'slider__label--size_sm',
thumb: 'slider__thumb--size_sm',
valueText: 'slider__valueText--size_sm',
track: 'slider__track--size_sm',
range: 'slider__range--size_sm',
control: 'slider__control--size_sm',
markerGroup: 'slider__markerGroup--size_sm',
marker: 'slider__marker--size_sm',
},
md: {
root: 'slider__root--size_md',
label: 'slider__label--size_md',
thumb: 'slider__thumb--size_md',
valueText: 'slider__valueText--size_md',
track: 'slider__track--size_md',
range: 'slider__range--size_md',
control: 'slider__control--size_md',
markerGroup: 'slider__markerGroup--size_md',
marker: 'slider__marker--size_md',
},
lg: {
root: 'slider__root--size_lg',
label: 'slider__label--size_lg',
thumb: 'slider__thumb--size_lg',
valueText: 'slider__valueText--size_lg',
track: 'slider__track--size_lg',
range: 'slider__range--size_lg',
control: 'slider__control--size_lg',
markerGroup: 'slider__markerGroup--size_lg',
marker: 'slider__marker--size_lg',
},
},
},
},
{ twMerge: false },
)
Not yet available