Slider
מחוון לבחירת ערך יחיד או טווח בין שני גבולות.
- דפדפנים
- Chrome 123+, Firefox 121+, Safari 17.5+
- שכבה
- 0
- גודל חבילה דחוסה
- 501 B
- מגבלת פריסה כפויה
- 0 ms
- מגבלת Axe
- 0
- תואם SSR
- כן
- חוזה מפורסם
- סביבת בדיקות
מגרש ניסויים
Slider
מחוון ברירת מחדל
מחוון מבוקר
מחוון עם סימונים
0.5×1×1.5×2×
מחוון טווח
טיוטהרגילגבוהמרבי
מחוון אנכי
קרנוחחם
מחוון מושבת
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
"use client";
import { useState } from "react";
import { Slider } from "@gunkin/uiify";
import { SliderClient } from "@gunkin/uiify/components/slider/client";
export default function Example() {
const [volume, setVolume] = useState(40);
const [value, setValue] = useState(70);
return (
<div>
<label>
<span>
Volume: <output htmlFor="example-volume">{volume}%</output>
</span>
<Slider aria-label="Volume" id="example-volume" className="" onValueChange={setVolume} value={volume} />
</label>
<label>
<span>
Quality: <output htmlFor="example-quality">{value}%</output>
</span>
<SliderClient
aria-label="Quality"
id="example-quality"
className=""
marks={[
{ value: 0, label: "Draft" },
{ value: 25, label: "Standard" },
{ value: 70, label: "High" },
{ value: 100, label: "Ultra" },
]}
max={100}
min={0}
onValueChange={(next) => {
if (typeof next === "number") setValue(next);
}}
step={null}
value={value}
/>
</label>
</div>
);
}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
/* Native controls stay visible until hydration; the client entry then adds a
labeled track while retaining the real range inputs for input semantics. */
@layer components {
[data-uiify-slider],
[data-uiify-slider-client] {
--uiify-slider-track-size: 0.375rem;
--uiify-slider-track-radius: 999px;
--uiify-slider-thumb-size: 1.125rem;
}
[data-uiify-slider] {
box-sizing: border-box;
display: block;
inline-size: 100%;
max-inline-size: 22rem;
min-inline-size: 14rem;
min-block-size: var(--control-md);
padding-inline: 0.5625rem;
appearance: none;
background-color: transparent;
cursor: pointer;
}
[data-uiify-slider]::-webkit-slider-runnable-track {
block-size: var(--uiify-slider-track-size);
border-radius: var(--uiify-slider-track-radius);
background: linear-gradient(
to right,
var(--primary) 0 var(--uiify-slider-progress, 50%),
var(--muted) var(--uiify-slider-progress, 50%) 100%
);
}
[data-uiify-slider]::-webkit-slider-thumb {
box-sizing: border-box;
inline-size: var(--uiify-slider-thumb-size);
block-size: var(--uiify-slider-thumb-size);
border: 2px solid var(--background);
border-radius: 50%;
background: var(--primary);
box-shadow: 0 0 0 1px var(--primary);
margin-block-start: calc((var(--uiify-slider-track-size) - var(--uiify-slider-thumb-size)) / 2);
appearance: none;
}
[data-uiify-slider]::-moz-range-thumb {
box-sizing: border-box;
inline-size: var(--uiify-slider-thumb-size);
block-size: var(--uiify-slider-thumb-size);
border: 2px solid var(--background);
border-radius: 50%;
background: var(--primary);
box-shadow: 0 0 0 1px var(--primary);
}
[data-uiify-slider]::-moz-range-track {
block-size: var(--uiify-slider-track-size);
border: 0;
border-radius: var(--uiify-slider-track-radius);
background: linear-gradient(
to right,
var(--primary) 0 var(--uiify-slider-progress, 50%),
var(--muted) var(--uiify-slider-progress, 50%) 100%
);
}
[data-uiify-slider]::-moz-range-progress {
background: transparent;
}
[data-uiify-slider]:dir(rtl)::-webkit-slider-runnable-track {
background-image: linear-gradient(
to left,
var(--primary) 0 var(--uiify-slider-progress, 50%),
var(--muted) var(--uiify-slider-progress, 50%) 100%
);
}
[data-uiify-slider]:dir(rtl)::-moz-range-track {
background-image: linear-gradient(
to left,
var(--primary) 0 var(--uiify-slider-progress, 50%),
var(--muted) var(--uiify-slider-progress, 50%) 100%
);
}
[data-uiify-slider]:focus-visible {
outline: 3px solid var(--ring);
outline-offset: 0.25rem;
}
[data-uiify-slider]:disabled,
[data-uiify-slider][data-disabled] {
opacity: 0.55;
cursor: not-allowed;
}
[data-uiify-slider-client] {
position: relative;
display: grid;
align-items: center;
inline-size: 100%;
max-inline-size: 22rem;
min-inline-size: 14rem;
min-block-size: var(--control-md);
accent-color: var(--primary);
}
[data-uiify-slider-client] > input[data-part="thumb"] {
position: absolute;
inset: 0;
inline-size: 100%;
block-size: 100%;
margin: 0;
accent-color: var(--primary);
opacity: 0.001;
}
[data-uiify-slider-client] [data-part="track"] {
position: absolute;
display: block;
inset-inline: 0.5625rem;
inset-block-start: 50%;
block-size: var(--uiify-slider-track-size);
border-radius: var(--uiify-slider-track-radius);
background: var(--muted);
pointer-events: none;
translate: 0 -50%;
}
[data-uiify-slider-client][data-enhanced][data-range] > input[data-part="thumb"]:first-of-type {
clip-path: inset(0 calc(100% - var(--uiify-slider-middle)) 0 0);
}
[data-uiify-slider-client][data-enhanced][data-range] > input[data-part="thumb"]:last-of-type {
clip-path: inset(0 0 0 var(--uiify-slider-middle));
}
[data-uiify-slider-client] [data-part="range"] {
position: absolute;
inset-block: 0;
inset-inline-start: var(--uiify-slider-start);
inline-size: calc(var(--uiify-slider-end) - var(--uiify-slider-start));
border-radius: var(--uiify-slider-track-radius);
background: var(--primary);
}
[data-uiify-slider-client] [data-part="mark"] {
position: absolute;
z-index: 1;
inset-block-start: calc(50% + 0.75rem);
inset-inline-start: var(--uiify-slider-position);
display: grid;
justify-items: center;
gap: 0.25rem;
color: var(--muted-foreground);
font-size: 0.75rem;
line-height: 1;
text-align: center;
translate: -50% 0;
}
[data-uiify-slider-client] [data-part="mark"]::before {
inline-size: 1px;
block-size: 0.4rem;
background: currentcolor;
content: "";
}
[data-uiify-slider-client] [data-part="visual-thumb"] {
position: absolute;
z-index: 2;
inset-block-start: 50%;
inset-inline-start: var(--uiify-slider-position);
inline-size: var(--uiify-slider-thumb-size);
aspect-ratio: 1;
border: 2px solid var(--background);
border-radius: 50%;
background: var(--primary);
box-shadow: 0 0 0 1px var(--primary);
translate: -50% -50%;
}
[data-uiify-slider-client]:has(input:focus-visible) [data-part="track"] {
outline: 3px solid var(--ring);
outline-offset: 0.25rem;
}
[data-uiify-slider-client][data-disabled] {
opacity: 0.55;
cursor: not-allowed;
}
[data-uiify-slider-client][data-disabled] > input {
cursor: not-allowed;
}
[data-uiify-slider-client][data-orientation="vertical"] {
inline-size: 14rem;
max-inline-size: none;
block-size: 3rem;
writing-mode: vertical-rl;
}
[data-uiify-slider-client][data-orientation="vertical"] [data-part="track"] {
inset-inline: 0.5625rem;
inset-block: 50% auto;
inline-size: auto;
block-size: 0.375rem;
translate: 50% 0;
}
[data-uiify-slider-client][data-enhanced][data-range][data-orientation="vertical"]
> input[data-part="thumb"]:first-of-type {
clip-path: inset(0 0 calc(100% - var(--uiify-slider-middle)) 0);
}
[data-uiify-slider-client][data-enhanced][data-range][data-orientation="vertical"]
> input[data-part="thumb"]:last-of-type {
clip-path: inset(var(--uiify-slider-middle) 0 0 0);
}
[data-uiify-slider-client][data-orientation="vertical"] [data-part="range"] {
inset-block: 0;
inset-inline: var(--uiify-slider-start) auto;
inline-size: calc(var(--uiify-slider-end) - var(--uiify-slider-start));
block-size: 100%;
}
[data-uiify-slider-client][data-orientation="vertical"] [data-part="mark"] {
inset-block-start: var(--uiify-slider-position);
inset-inline: calc(50% + 0.75rem) auto;
justify-items: start;
writing-mode: horizontal-tb;
translate: 0 -50%;
}
[data-uiify-slider-client][data-orientation="vertical"] [data-part="mark"]::before {
inline-size: 0.4rem;
block-size: 1px;
}
[data-uiify-slider-client][data-orientation="vertical"] [data-part="visual-thumb"] {
inset-block-start: 50%;
inset-inline-start: var(--uiify-slider-position);
translate: 50% -50%;
}
}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
"use client";
import { useState } from "react";
import { Slider } from "@gunkin/uiify";
import { SliderClient } from "@gunkin/uiify/components/slider/client";
export default function Example() {
const [volume, setVolume] = useState(40);
const [value, setValue] = useState(70);
return (
<div>
<label>
<span>
Volume: <output htmlFor="example-volume">{volume}%</output>
</span>
<Slider
aria-label="Volume"
id="example-volume"
className={
"[--uiify-slider-track-size:0.375rem] [--uiify-slider-track-radius:999px] [--uiify-slider-thumb-size:1.1" +
"25rem] box-border block w-full [max-inline-size:22rem] [min-inline-size:14rem] [min-block-size:var(--co" +
"ntrol-md)] [padding-inline:0.5625rem] appearance-none bg-transparent cursor-pointer [&::-webkit-slider-" +
"runnable-track]:[block-size:var(--uiify-slider-track-size)] [&::-webkit-slider-runnable-track]:[border-" +
"radius:var(--uiify-slider-track-radius)] [&::-webkit-slider-runnable-track]:[background:linear-gradient" +
"(to_right,var(--primary)_0_var(--uiify-slider-progress,50%),var(--muted)_var(--uiify-slider-progress,50" +
"%)_100%)] [&::-webkit-slider-thumb]:box-border [&::-webkit-slider-thumb]:[inline-size:var(--uiify-slide" +
"r-thumb-size)] [&::-webkit-slider-thumb]:[block-size:var(--uiify-slider-thumb-size)] [&::-webkit-slider" +
"-thumb]:[border:2px_solid_var(--background)] [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-" +
"thumb]:bg-primary [&::-webkit-slider-thumb]:[box-shadow:0_0_0_1px_var(--primary)] [&::-webkit-slider-th" +
"umb]:[margin-block-start:calc((var(--uiify-slider-track-size)_-_var(--uiify-slider-thumb-size))_/_2)] [" +
"&::-webkit-slider-thumb]:appearance-none [&::-moz-range-thumb]:box-border [&::-moz-range-thumb]:[inline" +
"-size:var(--uiify-slider-thumb-size)] [&::-moz-range-thumb]:[block-size:var(--uiify-slider-thumb-size)]" +
" [&::-moz-range-thumb]:[border:2px_solid_var(--background)] [&::-moz-range-thumb]:rounded-full [&::-moz" +
"-range-thumb]:bg-primary [&::-moz-range-thumb]:[box-shadow:0_0_0_1px_var(--primary)] [&::-moz-range-tra" +
"ck]:[block-size:var(--uiify-slider-track-size)] [&::-moz-range-track]:border-0 [&::-moz-range-track]:bo" +
"rder-none [&::-moz-range-track]:[border-radius:var(--uiify-slider-track-radius)] [&::-moz-range-track]:" +
"[background:linear-gradient(to_right,var(--primary)_0_var(--uiify-slider-progress,50%),var(--muted)_var" +
"(--uiify-slider-progress,50%)_100%)] [&::-moz-range-progress]:bg-transparent [&:dir(rtl)::-webkit-slide" +
"r-runnable-track]:[background-image:linear-gradient(to_left,var(--primary)_0_var(--uiify-slider-progres" +
"s,50%),var(--muted)_var(--uiify-slider-progress,50%)_100%)] [&:dir(rtl)::-moz-range-track]:[background-" +
"image:linear-gradient(to_left,var(--primary)_0_var(--uiify-slider-progress,50%),var(--muted)_var(--uiif" +
"y-slider-progress,50%)_100%)] focus-visible:[outline:3px_solid_var(--ring)] focus-visible:[outline-offs" +
"et:0.25rem] disabled:opacity-55 disabled:cursor-not-allowed data-[disabled]:opacity-55 data-[disabled]:" +
"cursor-not-allowed"
}
onValueChange={setVolume}
value={volume}
/>
</label>
<label>
<span>
Quality: <output htmlFor="example-quality">{value}%</output>
</span>
<SliderClient
aria-label="Quality"
id="example-quality"
className={
"[--uiify-slider-track-size:0.375rem] [--uiify-slider-track-radius:999px] [--uiify-slider-thumb-size:1.1" +
"25rem] box-border block w-full [max-inline-size:22rem] [min-inline-size:14rem] [min-block-size:var(--co" +
"ntrol-md)] [padding-inline:0.5625rem] appearance-none bg-transparent cursor-pointer [&::-webkit-slider-" +
"runnable-track]:[block-size:var(--uiify-slider-track-size)] [&::-webkit-slider-runnable-track]:[border-" +
"radius:var(--uiify-slider-track-radius)] [&::-webkit-slider-runnable-track]:[background:linear-gradient" +
"(to_right,var(--primary)_0_var(--uiify-slider-progress,50%),var(--muted)_var(--uiify-slider-progress,50" +
"%)_100%)] [&::-webkit-slider-thumb]:box-border [&::-webkit-slider-thumb]:[inline-size:var(--uiify-slide" +
"r-thumb-size)] [&::-webkit-slider-thumb]:[block-size:var(--uiify-slider-thumb-size)] [&::-webkit-slider" +
"-thumb]:[border:2px_solid_var(--background)] [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-" +
"thumb]:bg-primary [&::-webkit-slider-thumb]:[box-shadow:0_0_0_1px_var(--primary)] [&::-webkit-slider-th" +
"umb]:[margin-block-start:calc((var(--uiify-slider-track-size)_-_var(--uiify-slider-thumb-size))_/_2)] [" +
"&::-webkit-slider-thumb]:appearance-none [&::-moz-range-thumb]:box-border [&::-moz-range-thumb]:[inline" +
"-size:var(--uiify-slider-thumb-size)] [&::-moz-range-thumb]:[block-size:var(--uiify-slider-thumb-size)]" +
" [&::-moz-range-thumb]:[border:2px_solid_var(--background)] [&::-moz-range-thumb]:rounded-full [&::-moz" +
"-range-thumb]:bg-primary [&::-moz-range-thumb]:[box-shadow:0_0_0_1px_var(--primary)] [&::-moz-range-tra" +
"ck]:[block-size:var(--uiify-slider-track-size)] [&::-moz-range-track]:border-0 [&::-moz-range-track]:bo" +
"rder-none [&::-moz-range-track]:[border-radius:var(--uiify-slider-track-radius)] [&::-moz-range-track]:" +
"[background:linear-gradient(to_right,var(--primary)_0_var(--uiify-slider-progress,50%),var(--muted)_var" +
"(--uiify-slider-progress,50%)_100%)] [&::-moz-range-progress]:bg-transparent [&:dir(rtl)::-webkit-slide" +
"r-runnable-track]:[background-image:linear-gradient(to_left,var(--primary)_0_var(--uiify-slider-progres" +
"s,50%),var(--muted)_var(--uiify-slider-progress,50%)_100%)] [&:dir(rtl)::-moz-range-track]:[background-" +
"image:linear-gradient(to_left,var(--primary)_0_var(--uiify-slider-progress,50%),var(--muted)_var(--uiif" +
"y-slider-progress,50%)_100%)] focus-visible:[outline:3px_solid_var(--ring)] focus-visible:[outline-offs" +
"et:0.25rem] disabled:opacity-55 disabled:cursor-not-allowed data-[disabled]:opacity-55 data-[disabled]:" +
"cursor-not-allowed"
}
marks={[
{ value: 0, label: "Draft" },
{ value: 25, label: "Standard" },
{ value: 70, label: "High" },
{ value: 100, label: "Ultra" },
]}
max={100}
min={0}
onValueChange={(next) => {
if (typeof next === "number") setValue(next);
}}
step={null}
value={value}
/>
</label>
</div>
);
}API
Slider
| מאפיין | טיפוס | ברירת מחדל | תיאור |
|---|---|---|---|
value | number | — | הערך הנוכחי, ההופך את המחוון למבוקר. |
defaultValue | number | — | הערך ההתחלתי של המחוון הלא מבוקר, שלאחר מכן מנוהל על ידי קלט הטווח המובנה. |
onValueChange | (value: number) => void | — | נקראת עם המספר החדש בכל תזוזה של המחוון. |
min | number | 0 | הערך הנמוך ביותר שניתן לבחור. |
max | number | 100 | הערך הגבוה ביותר שניתן לבחור. |
step | number | 1 | ההפרש בין ערכים שניתן לבחור. |
disabled | boolean | false | משבית את הקלט המובנה ומגדיר את המאפיין data-disabled. |
render | ReactElement | ((props, state) => ReactElement) | — | החלפת האלמנט המוצג תוך שימור ההתנהגות וקישורי הנגישות. |
SliderClient
| מאפיין | טיפוס | ברירת מחדל | תיאור |
|---|---|---|---|
value | number | readonly [number, number] | — | ערך מבוקר; זוג ערכים מציג ידית תחתונה ועליונה. |
defaultValue | number | readonly [number, number] | — | ערך התחלתי לקלט הטווח המובנה או לטווח בעל שתי ידיות. |
onValueChange | (value: number | readonly [number, number]) => void | — | נקראת כשהערך הנבחר או הטווח המסודר משתנים. |
min | number | 0 | הערך הנמוך ביותר שניתן לבחור. |
max | number | 100 | הערך הגבוה ביותר שניתן לבחור. |
step | number | null | 1 | צעד מספרי משמר את הדילוג המובנה לפני ההידרציה; null מגביל את הערכים ל-min, max וסימונים לאחר ההידרציה. |
marks | readonly { value: number; label?: ReactNode }[] | — | תוויות שנתות ונקודות הצמדה כאשר step הוא null. |
orientation | "horizontal" | "vertical" | "horizontal" | כיוון הפריסה של הפקד והסימונים שלו. |
thumbLabels | readonly [string, string] | — | שמות נגישים לידיות הטווח התחתונה והעליונה. |
slotProps | SliderClientSlotProps | — | מאפיינים מובנים למסילה, לטווח, לסימונים, לידיות החזותיות ולקלטים המובנים שנוצרים. הסימונים מזוהים לפי ערכיהם וניתן למקד אותם גם לפי אינדקס התצוגה; מאפייני הידיות משתמשים במפתחות value, minimum ו-maximum. |
disabled | boolean | false | משבית את כל קלטי הטווח המובנים. |
render | ReactElement | ((props, state) => ReactElement) | — | החלפת האלמנט המוצג תוך שימור ההתנהגות וקישורי הנגישות. |
מקלדת
| מקש | פעולה |
|---|---|
| Arrow keys | שינוי שדה הטווח המובנה והממוקד בצעד אחד או עד לעצירה |
| Home / End | העברת הידית הממוקדת למינימום או למקסימום |
| Tab | מעבר בין הידית התחתונה לעליונה של הטווח |
נגישות
Slider מרנדר שדה טווח מובנה שפועל לפני הידרציה וכש-JavaScript מושבת. גם SliderClient מרנדר שדות טווח מובנים בשרת, ואז שולט בהם לאחר הידרציה עבור ערכי טווח, סימונים עם תוויות והצמדה לא אחידה. step מספרי שומר על צעדים מובנים לפני הידרציה; הצמדה לסימונים באמצעות step={null} מתחילה לאחר הידרציה. תנו למחוון יחיד aria-label או aria-labelledby; לשתי ידיות הטווח תנו thumbLabels.
נקודות חיבור לעיצוב
data-uiify-sliderdata-uiify-slider-clientdata-part="root"data-part="track"data-part="range"data-part="mark"data-part="thumb"data-orientationdata-disableddata-enhanced--uiify-slider-start--uiify-slider-end--uiify-slider-position