diff --git a/thaw/src/slider/docs/mod.md b/thaw/src/slider/docs/mod.md
index 9dd664cd..ece72a05 100644
--- a/thaw/src/slider/docs/mod.md
+++ b/thaw/src/slider/docs/mod.md
@@ -18,6 +18,16 @@ view! {
}
```
+### Vertical
+
+```rust demo
+let value = RwSignal::new(6.0);
+
+view! {
+
+}
+```
+
## Slider Label
```rust demo
@@ -50,6 +60,7 @@ view! {
| min | `Signal` | `0` | Min value of the slider. |
| max | `Signal` | `100` | Max value of the slider. |
| step | `Signal` | `0` | The step in which value is incremented. |
+| vertical | `Signal` | `false` | Render the Slider in a vertical orientation, smallest value on the bottom. |
| children | `Option` | `None` | |
### SliderLabel props
diff --git a/thaw/src/slider/docs/range-slider.md b/thaw/src/slider/docs/range-slider.md
index c395326e..7c1164d0 100644
--- a/thaw/src/slider/docs/range-slider.md
+++ b/thaw/src/slider/docs/range-slider.md
@@ -21,6 +21,16 @@ view! {
}
```
+### Vertical
+
+```rust demo
+let value = RwSignal::new((6.0, 8.0));
+
+view! {
+
+}
+```
+
### SliderLabel
```rust demo
@@ -43,11 +53,12 @@ view! {
### RangeSlider Props
-| Name | Type | Default | Description |
-| ----- | ------------------- | -------------------- | ------------------------------------------- |
-| class | `MaybeProp` | `Default::default()` | |
-| style | `MaybeProp` | `Default::default()` | |
-| value | `Model<(f64, f64)>` | `(0.0, 0.0)` | The current value of the controlled Slider. |
-| min | `Signal` | `0` | Min value of the slider. |
-| max | `Signal` | `100` | Max value of the slider. |
-| step | `Signal` | `0` | The step in which value is incremented. |
+| Name | Type | Default | Description |
+| --- | --- | --- | --- |
+| class | `MaybeProp` | `Default::default()` | |
+| style | `MaybeProp` | `Default::default()` | |
+| value | `Model<(f64, f64)>` | `(0.0, 0.0)` | The current value of the controlled Slider. |
+| min | `Signal` | `0` | Min value of the slider. |
+| max | `Signal` | `100` | Max value of the slider. |
+| step | `Signal` | `0` | The step in which value is incremented. |
+| vertical | `Signal` | `false` | Render the Slider in a vertical orientation, smallest value on the bottom. |
diff --git a/thaw/src/slider/mod.rs b/thaw/src/slider/mod.rs
index 9a2057f5..314ef569 100644
--- a/thaw/src/slider/mod.rs
+++ b/thaw/src/slider/mod.rs
@@ -1,156 +1,7 @@
mod range_slider;
+mod slider;
mod slider_label;
pub use range_slider::*;
+pub use slider::*;
pub use slider_label::SliderLabel;
-
-use crate::{FieldInjection, FieldValidationState, Rule};
-use leptos::{context::Provider, ev, prelude::*};
-use std::ops::Deref;
-use thaw_components::OptionComp;
-use thaw_utils::{class_list, mount_style, Model};
-
-#[component]
-pub fn Slider(
- #[prop(optional, into)] class: MaybeProp,
- #[prop(optional, into)] id: MaybeProp,
- /// A string specifying a name for the input control.
- /// This name is submitted along with the control's value when the form data is submitted.
- #[prop(optional, into)]
- name: MaybeProp,
- /// The rules to validate Field.
- #[prop(optional, into)]
- rules: Vec,
- /// The current value of the controlled Slider.
- #[prop(optional, into)]
- value: Model,
- /// Min value of the slider.
- #[prop(default = 0f64.into(), into)]
- min: Signal,
- /// Max value of the slider.
- #[prop(default = 100f64.into(), into)]
- max: Signal,
- /// The step in which value is incremented.
- #[prop(optional, into)]
- step: MaybeProp,
- #[prop(optional)] children: Option,
-) -> impl IntoView {
- mount_style("slider", include_str!("./slider.css"));
- let (id, name) = FieldInjection::use_id_and_name(id, name);
- let validate = Rule::validate(rules, value, name);
- let is_chldren = children.is_some();
- let current_value = Memo::new(move |_| {
- let max = max.get();
- let min = min.get();
- let v = value.get();
- if v > max {
- max
- } else if v < min {
- min
- } else {
- v
- }
- });
-
- let on_input = move |e: ev::Event| {
- if let Ok(range_value) = event_target_value(&e).parse::() {
- value.set(range_value);
- validate.run(Some(SliderRuleTrigger::Input));
- }
- };
-
- let css_vars = move || {
- let max = max.get();
- let min = min.get();
- let mut css_vars = format!(
- "--thaw-slider--direction: 90deg;--thaw-slider--progress: {:.2}%;",
- if max == min {
- 0.0
- } else {
- (current_value.get() - min) / (max - min) * 100.0
- }
- );
-
- if is_chldren {
- css_vars.push_str(&format!("--thaw-slider--max: {:.2};", max));
- css_vars.push_str(&format!("--thaw-slider--min: {:.2};", min));
- }
-
- if let Some(step) = step.get() {
- if step > 0.0 {
- css_vars.push_str(&format!(
- "--thaw-slider--steps-percent: {:.2}%",
- step * 100.0 / (max - min)
- ));
- }
- }
- css_vars
- };
-
- view! {
-
-
-
-
-
-
- {children()}
-
-
-
- }
-}
-
-#[derive(Clone)]
-pub(crate) struct SliderInjection {
- pub max: Signal,
- pub min: Signal,
-}
-
-impl SliderInjection {
- pub fn expect_context() -> Self {
- expect_context()
- }
-}
-
-#[derive(Debug, Default, PartialEq, Clone, Copy)]
-pub enum SliderRuleTrigger {
- #[default]
- Input,
-}
-
-pub struct SliderRule(Rule);
-
-impl SliderRule {
- pub fn validator(
- f: impl Fn(&f64, Signal>) -> Result<(), FieldValidationState>
- + Send
- + Sync
- + 'static,
- ) -> Self {
- Self(Rule::validator(f))
- }
-
- pub fn with_trigger(self, trigger: SliderRuleTrigger) -> Self {
- Self(Rule::with_trigger(self.0, trigger))
- }
-}
-
-impl Deref for SliderRule {
- type Target = Rule;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
diff --git a/thaw/src/slider/range_slider/mod.rs b/thaw/src/slider/range_slider/mod.rs
index cb3b0abe..d5684e3b 100644
--- a/thaw/src/slider/range_slider/mod.rs
+++ b/thaw/src/slider/range_slider/mod.rs
@@ -1,5 +1,5 @@
use super::super::SliderInjection;
-use leptos::{context::Provider, ev, html, logging, prelude::*};
+use leptos::{context::Provider, ev, html, prelude::*};
use thaw_components::OptionComp;
use thaw_utils::{class_list, mount_style, Model};
@@ -17,6 +17,9 @@ pub fn RangeSlider(
/// The step in which value is incremented.
#[prop(optional, into)]
step: MaybeProp,
+ /// Render the Slider in a vertical orientation, smallest value on the bottom.
+ #[prop(optional, into)]
+ vertical: Signal,
#[prop(optional)] children: Option,
) -> impl IntoView {
mount_style("range-slider", include_str!("./range-slider.css"));
@@ -35,8 +38,6 @@ pub fn RangeSlider(
left = closest_multiple(left, step, min, max);
right = closest_multiple(right, step, min, max);
- logging::log!("l {} r {}", left, right);
-
(left, right)
});
@@ -58,6 +59,13 @@ pub fn RangeSlider(
let css_vars = move || {
let mut css_vars = style.get().unwrap_or_default();
+
+ if vertical.get() {
+ css_vars.push_str(";--thaw-slider--direction: 0deg;");
+ } else {
+ css_vars.push_str(";--thaw-slider--direction: 90deg;");
+ }
+
if let Some(step) = step.get() {
if step > 0.0 {
let max = max.get();
@@ -96,14 +104,20 @@ pub fn RangeSlider(
let on_click = move |e: web_sys::MouseEvent| {
if let Some(slider) = slider_ref.get_untracked() {
- let rect = slider.get_bounding_client_rect();
- let ev_x = f64::from(e.x());
let min = min.get_untracked();
let max = max.get_untracked();
- let percentage = (ev_x - rect.x()) / rect.width() * (max - min);
- let (left, right) = current_value.get();
+ let rect = slider.get_bounding_client_rect();
+ let percentage = if vertical.get_untracked() {
+ let ev_y = f64::from(e.y());
+ let slider_height = rect.height();
+ (slider_height + rect.y() - ev_y) / slider_height * (max - min)
+ } else {
+ let ev_x = f64::from(e.x());
+ (ev_x - rect.x()) / rect.width() * (max - min)
+ };
+ let (left, right) = current_value.get();
let left_diff = (left - percentage).abs();
let right_diff = (right - percentage).abs();
@@ -132,20 +146,39 @@ pub fn RangeSlider(
let on_mousemove = move || {
let mousemove = window_event_listener(ev::mousemove, move |e| {
if let Some(slider_el) = slider_ref.get_untracked() {
+ let min = min.get_untracked();
+ let max = max.get_untracked();
+
let slider_rect = slider_el.get_bounding_client_rect();
- let slider_width = slider_rect.width();
- let slider_x = slider_rect.x();
- let ev_x = f64::from(e.x());
- let length = if ev_x < slider_x {
- 0.0
- } else if ev_x > slider_x + slider_width {
- slider_width
+ let percentage = if vertical.get_untracked() {
+ let ev_y = f64::from(e.y());
+ let slider_y = slider_rect.y();
+ let slider_height = slider_rect.height();
+
+ let length = if ev_y < slider_y {
+ 0.0
+ } else if ev_y > slider_y + slider_height {
+ slider_height
+ } else {
+ slider_y + slider_height - ev_y
+ };
+
+ length / slider_height * (max - min)
} else {
- ev_x - slider_x
+ let ev_x = f64::from(e.x());
+ let slider_x = slider_rect.x();
+ let slider_width = slider_rect.width();
+
+ let length = if ev_x < slider_x {
+ 0.0
+ } else if ev_x > slider_x + slider_width {
+ slider_width
+ } else {
+ ev_x - slider_x
+ };
+
+ length / slider_width * (max - min)
};
- let min = min.get_untracked();
- let max = max.get_untracked();
- let percentage = length / slider_width * (max - min);
if left_mousemove.get_value() {
update_value(percentage, current_value.get_untracked().1);
@@ -182,7 +215,11 @@ pub fn RangeSlider(
view! {
-
+
{children()}
diff --git a/thaw/src/slider/range_slider/range-slider.css b/thaw/src/slider/range_slider/range-slider.css
index 8f43a483..daf84b71 100644
--- a/thaw/src/slider/range_slider/range-slider.css
+++ b/thaw/src/slider/range_slider/range-slider.css
@@ -1,20 +1,28 @@
.thaw-range-slider {
position: relative;
- min-width: 120px;
min-height: 32px;
display: inline-grid;
- grid-template-columns:
- 1fr calc(100% - 20px)
- 1fr;
- grid-template-rows: 1fr 20px 1fr;
justify-items: center;
align-items: center;
touch-action: none;
cursor: pointer;
+ --thaw-slider__rail--size: 4px;
--thaw-slider__thumb--size: 20px;
}
+.thaw-range-slider--horizontal {
+ min-width: 120px;
+ grid-template-rows: 1fr var(--thaw-slider__thumb--size) 1fr;
+ grid-template-columns: 1fr calc(100% - var(--thaw-slider__thumb--size)) 1fr;
+}
+
+.thaw-range-slider--vertical {
+ min-height: 120px;
+ grid-template-rows: 1fr calc(100% - var(--thaw-slider__thumb--size)) 1fr;
+ grid-template-columns: 1fr var(--thaw-slider__thumb--size) 1fr;
+}
+
.thaw-range-slider__rail {
position: relative;
forced-color-adjust: none;
@@ -22,10 +30,8 @@
grid-column-start: 2;
grid-row-end: 2;
grid-row-start: 2;
- width: 100%;
- height: 4px;
background-image: linear-gradient(
- 90deg,
+ var(--thaw-slider--direction),
var(--colorNeutralStrokeAccessible) 0%
var(--thaw-range-slider--left-progress),
var(--colorCompoundBrandBackground)
@@ -39,16 +45,22 @@
pointer-events: none;
}
+.thaw-range-slider--horizontal .thaw-range-slider__rail {
+ width: 100%;
+ height: var(--thaw-slider__rail--size);
+}
+
+.thaw-range-slider--vertical .thaw-range-slider__rail {
+ width: var(--thaw-slider__rail--size);
+ height: 100%;
+}
+
.thaw-range-slider__rail::before {
content: "";
position: absolute;
- height: 4px;
- right: -1px;
- left: -1px;
-
background-image: repeating-linear-gradient(
- 90deg,
+ var(--thaw-slider--direction),
#0000 0%,
#0000 calc(var(--thaw-range-slider--steps-percent) - 1px),
var(--colorNeutralBackground1)
@@ -57,6 +69,18 @@
);
}
+.thaw-range-slider--horizontal .thaw-range-slider__rail::before {
+ height: var(--thaw-slider__rail--size);
+ right: -1px;
+ left: -1px;
+}
+
+.thaw-range-slider--vertical .thaw-range-slider__rail::before {
+ width: var(--thaw-slider__rail--size);
+ top: -1px;
+ bottom: -1px;
+}
+
.thaw-range-slider__thumb {
position: absolute;
forced-color-adjust: none;
@@ -64,15 +88,23 @@
grid-column-start: 2;
grid-row-end: 2;
grid-row-start: 2;
- height: 20px;
- width: 20px;
- left: var(--thaw-range-slider--progress);
+ height: var(--thaw-slider__thumb--size);
+ width: var(--thaw-slider__thumb--size);
background-color: var(--colorCompoundBrandBackground);
outline-style: none;
/* pointer-events: none; */
border-radius: var(--borderRadiusCircular);
box-shadow: 0 0 0 4px var(--colorNeutralBackground1) inset;
+}
+
+.thaw-range-slider--horizontal .thaw-range-slider__thumb {
transform: translateX(-50%);
+ left: var(--thaw-range-slider--progress);
+}
+
+.thaw-range-slider--vertical .thaw-range-slider__thumb {
+ transform: translateY(50%);
+ bottom: var(--thaw-range-slider--progress);
}
.thaw-range-slider__thumb:hover {
@@ -100,6 +132,14 @@
.thaw-range-slider__datalist {
display: block;
position: absolute;
+}
+
+.thaw-range-slider--horizontal .thaw-range-slider__datalist {
width: 100%;
- top: 24px;
+ top: calc(var(--thaw-slider__thumb--size) + 4px);
+}
+
+.thaw-range-slider--vertical .thaw-range-slider__datalist {
+ height: 100%;
+ left: calc(var(--thaw-slider__thumb--size) + 4px);
}
diff --git a/thaw/src/slider/slider/mod.rs b/thaw/src/slider/slider/mod.rs
new file mode 100644
index 00000000..137e6714
--- /dev/null
+++ b/thaw/src/slider/slider/mod.rs
@@ -0,0 +1,130 @@
+mod types;
+
+pub use types::*;
+
+use crate::{FieldInjection, Rule};
+use leptos::{context::Provider, ev, prelude::*};
+use thaw_components::OptionComp;
+use thaw_utils::{class_list, mount_style, Model};
+
+#[component]
+pub fn Slider(
+ #[prop(optional, into)] class: MaybeProp,
+ #[prop(optional, into)] id: MaybeProp,
+ /// A string specifying a name for the input control.
+ /// This name is submitted along with the control's value when the form data is submitted.
+ #[prop(optional, into)]
+ name: MaybeProp,
+ /// The rules to validate Field.
+ #[prop(optional, into)]
+ rules: Vec,
+ /// The current value of the controlled Slider.
+ #[prop(optional, into)]
+ value: Model,
+ /// Min value of the slider.
+ #[prop(default = 0f64.into(), into)]
+ min: Signal,
+ /// Max value of the slider.
+ #[prop(default = 100f64.into(), into)]
+ max: Signal,
+ /// The step in which value is incremented.
+ #[prop(optional, into)]
+ step: MaybeProp,
+ /// Render the Slider in a vertical orientation, smallest value on the bottom.
+ #[prop(optional, into)]
+ vertical: Signal,
+ #[prop(optional)] children: Option,
+) -> impl IntoView {
+ mount_style("slider", include_str!("./slider.css"));
+ let (id, name) = FieldInjection::use_id_and_name(id, name);
+ let validate = Rule::validate(rules, value, name);
+ let is_chldren = children.is_some();
+ let current_value = Memo::new(move |_| {
+ let max = max.get();
+ let min = min.get();
+ let v = value.get();
+ if v > max {
+ max
+ } else if v < min {
+ min
+ } else {
+ v
+ }
+ });
+
+ let on_input = move |e: ev::Event| {
+ if let Ok(range_value) = event_target_value(&e).parse::() {
+ value.set(range_value);
+ validate.run(Some(SliderRuleTrigger::Input));
+ }
+ };
+
+ let css_vars = move || {
+ let max = max.get();
+ let min = min.get();
+ let mut css_vars = format!(
+ "--thaw-slider--progress: {:.2}%;",
+ if max == min {
+ 0.0
+ } else {
+ (current_value.get() - min) / (max - min) * 100.0
+ }
+ );
+
+ if vertical.get() {
+ css_vars.push_str("--thaw-slider--direction: 0deg;");
+ } else {
+ css_vars.push_str("--thaw-slider--direction: 90deg;");
+ }
+
+ if is_chldren {
+ css_vars.push_str(&format!("--thaw-slider--max: {:.2};", max));
+ css_vars.push_str(&format!("--thaw-slider--min: {:.2};", min));
+ }
+
+ if let Some(step) = step.get() {
+ if step > 0.0 {
+ css_vars.push_str(&format!(
+ "--thaw-slider--steps-percent: {:.2}%",
+ step * 100.0 / (max - min)
+ ));
+ }
+ }
+ css_vars
+ };
+
+ view! {
+
+
+
+
+
+
+ {children()}
+
+
+
+ }
+}
diff --git a/thaw/src/slider/slider.css b/thaw/src/slider/slider/slider.css
similarity index 77%
rename from thaw/src/slider/slider.css
rename to thaw/src/slider/slider/slider.css
index ec06052a..c372e8df 100644
--- a/thaw/src/slider/slider.css
+++ b/thaw/src/slider/slider/slider.css
@@ -1,12 +1,9 @@
.thaw-slider {
- min-width: 120px;
min-height: 32px;
justify-items: center;
touch-action: none;
display: inline-grid;
- grid-template-columns: 1fr calc(100% - var(--thaw-slider__thumb--size)) 1fr;
- grid-template-rows: 1fr var(--thaw-slider__thumb--size) 1fr;
position: relative;
align-items: center;
@@ -18,6 +15,18 @@
--thaw-slider__rail--color: var(--colorNeutralStrokeAccessible);
}
+.thaw-slider--horizontal {
+ min-width: 120px;
+ grid-template-rows: 1fr var(--thaw-slider__thumb--size) 1fr;
+ grid-template-columns: 1fr calc(100% - var(--thaw-slider__thumb--size)) 1fr;
+}
+
+.thaw-slider--vertical {
+ min-height: 120px;
+ grid-template-rows: 1fr calc(100% - var(--thaw-slider__thumb--size)) 1fr;
+ grid-template-columns: 1fr var(--thaw-slider__thumb--size) 1fr;
+}
+
.thaw-slider:hover {
--thaw-slider__progress--color: var(--colorCompoundBrandBackgroundHover);
--thaw-slider__thumb--color: var(--colorCompoundBrandBackgroundHover);
@@ -55,11 +64,18 @@
margin: 0;
padding: 0;
opacity: 0;
+ cursor: pointer;
+}
+.thaw-slider--horizontal .thaw-slider__input {
width: 100%;
height: var(--thaw-slider__thumb--size);
+}
- cursor: pointer;
+.thaw-slider--vertical .thaw-slider__input {
+ width: var(--thaw-slider__thumb--size);
+ height: 100%;
+ -webkit-appearance: slider-vertical;
}
.thaw-slider__rail {
@@ -69,8 +85,7 @@
grid-column-start: 2;
grid-row-end: 2;
grid-row-start: 2;
- width: 100%;
- height: var(--thaw-slider__rail--size);
+
background-image: linear-gradient(
var(--thaw-slider--direction),
var(--thaw-slider__progress--color) 0%,
@@ -82,14 +97,20 @@
pointer-events: none;
}
+.thaw-slider--horizontal .thaw-slider__rail {
+ width: 100%;
+ height: var(--thaw-slider__rail--size);
+}
+
+.thaw-slider--vertical .thaw-slider__rail {
+ width: var(--thaw-slider__rail--size);
+ height: 100%;
+}
+
.thaw-slider__rail::before {
content: "";
position: absolute;
- height: var(--thaw-slider__rail--size);
- right: -1px;
- left: -1px;
-
background-image: repeating-linear-gradient(
var(--thaw-slider--direction),
#0000 0%,
@@ -100,6 +121,18 @@
);
}
+.thaw-slider--horizontal .thaw-slider__rail::before {
+ height: var(--thaw-slider__rail--size);
+ right: -1px;
+ left: -1px;
+}
+
+.thaw-slider--vertical .thaw-slider__rail::before {
+ width: var(--thaw-slider__rail--size);
+ top: -1px;
+ bottom: -1px;
+}
+
.thaw-slider__thumb {
position: absolute;
@@ -111,7 +144,6 @@
height: var(--thaw-slider__thumb--size);
width: var(--thaw-slider__thumb--size);
- left: var(--thaw-slider--progress);
background-color: var(--thaw-slider__thumb--color);
outline-style: none;
@@ -119,8 +151,16 @@
border-radius: var(--borderRadiusCircular);
box-shadow: 0 0 0 calc(var(--thaw-slider__thumb--size) * 0.2)
var(--colorNeutralBackground1) inset;
+}
+.thaw-slider--horizontal .thaw-slider__thumb {
transform: translateX(-50%);
+ left: var(--thaw-slider--progress);
+}
+
+.thaw-slider--vertical .thaw-slider__thumb {
+ transform: translateY(50%);
+ bottom: var(--thaw-slider--progress);
}
.thaw-slider__thumb::before {
@@ -141,6 +181,14 @@
.thaw-slider__datalist {
display: block;
position: absolute;
+}
+
+.thaw-slider--horizontal .thaw-slider__datalist {
width: 100%;
top: calc(var(--thaw-slider__thumb--size) + 4px);
}
+
+.thaw-slider--vertical .thaw-slider__datalist {
+ height: 100%;
+ left: calc(var(--thaw-slider__thumb--size) + 4px);
+}
diff --git a/thaw/src/slider/slider/types.rs b/thaw/src/slider/slider/types.rs
new file mode 100644
index 00000000..180036fe
--- /dev/null
+++ b/thaw/src/slider/slider/types.rs
@@ -0,0 +1,47 @@
+use crate::{FieldValidationState, Rule};
+use leptos::prelude::*;
+use std::ops::Deref;
+
+#[derive(Clone, Copy)]
+pub(crate) struct SliderInjection {
+ pub max: Signal,
+ pub min: Signal,
+ pub vertical: Signal,
+}
+
+impl SliderInjection {
+ pub fn expect_context() -> Self {
+ expect_context()
+ }
+}
+
+#[derive(Debug, Default, PartialEq, Clone, Copy)]
+pub enum SliderRuleTrigger {
+ #[default]
+ Input,
+}
+
+pub struct SliderRule(Rule);
+
+impl SliderRule {
+ pub fn validator(
+ f: impl Fn(&f64, Signal>) -> Result<(), FieldValidationState>
+ + Send
+ + Sync
+ + 'static,
+ ) -> Self {
+ Self(Rule::validator(f))
+ }
+
+ pub fn with_trigger(self, trigger: SliderRuleTrigger) -> Self {
+ Self(Rule::with_trigger(self.0, trigger))
+ }
+}
+
+impl Deref for SliderRule {
+ type Target = Rule;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
diff --git a/thaw/src/slider/slider_label.css b/thaw/src/slider/slider_label.css
index 725911cb..8d67e037 100644
--- a/thaw/src/slider/slider_label.css
+++ b/thaw/src/slider/slider_label.css
@@ -1,5 +1,12 @@
.thaw-slider-label {
position: absolute;
display: inline-block;
+}
+
+.thaw-slider-label--horizontal {
transform: translateX(-50%);
}
+
+.thaw-slider-label--vertical {
+ transform: translateY(50%);
+}
diff --git a/thaw/src/slider/slider_label.rs b/thaw/src/slider/slider_label.rs
index d8e4cc36..4203e6bb 100644
--- a/thaw/src/slider/slider_label.rs
+++ b/thaw/src/slider/slider_label.rs
@@ -16,11 +16,23 @@ pub fn SliderLabel(
let style = move || {
let value = (value.get() - slider.min.get()) / (slider.max.get() - slider.min.get());
- format!("left: calc({} * (100% - var(--thaw-slider__thumb--size)) + var(--thaw-slider__thumb--size) / 2)", value)
+
+ if slider.vertical.get() {
+ format!("bottom: calc({} * (100% - var(--thaw-slider__thumb--size)) + var(--thaw-slider__thumb--size) / 2)", value)
+ } else {
+ format!("left: calc({} * (100% - var(--thaw-slider__thumb--size)) + var(--thaw-slider__thumb--size) / 2)", value)
+ }
};
view! {
-