diff --git a/.changeset/fresh-gifts-bathe.md b/.changeset/fresh-gifts-bathe.md
new file mode 100644
index 000000000..4549162d5
--- /dev/null
+++ b/.changeset/fresh-gifts-bathe.md
@@ -0,0 +1,5 @@
+---
+"bits-ui": patch
+---
+
+fix(Slider): update tick position calculation for consistent scaling
diff --git a/docs/content/components/slider.md b/docs/content/components/slider.md
index f4f0d7558..8a3e1ba12 100644
--- a/docs/content/components/slider.md
+++ b/docs/content/components/slider.md
@@ -4,7 +4,7 @@ description: Allows users to select a value from a continuous range by sliding a
---
@@ -151,11 +151,11 @@ If the `value` prop has more than one value, the slider will render multiple thu
{#snippet children({ ticks, thumbs })}
- {#each thumbs as index}
+ {#each thumbs as index (index)}
{/each}
- {#each ticks as index}
+ {#each ticks as index (index)}
{/each}
{/snippet}
@@ -164,6 +164,14 @@ If the `value` prop has more than one value, the slider will render multiple thu
To determine the number of ticks that will be rendered, you can simply divide the `max` value by the `step` value.
+
+
+{#snippet preview()}
+
+{/snippet}
+
+
+
## Single Type
Set the `type` prop to `"single"` to allow only one accordion item to be open at a time.
diff --git a/docs/src/lib/components/demos/index.ts b/docs/src/lib/components/demos/index.ts
index e41a189c1..81ca30452 100644
--- a/docs/src/lib/components/demos/index.ts
+++ b/docs/src/lib/components/demos/index.ts
@@ -57,6 +57,7 @@ export { default as ScrollAreaDemoCustom } from "./scroll-area-demo-custom.svelt
export { default as SeparatorDemo } from "./separator-demo.svelte";
export { default as SliderDemo } from "./slider-demo.svelte";
export { default as SliderDemoMultiple } from "./slider-demo-multiple.svelte";
+export { default as SliderDemoTicks } from "./slider-demo-ticks.svelte";
export { default as SwitchDemo } from "./switch-demo.svelte";
export { default as SwitchDemoCustom } from "./switch-demo-custom.svelte";
export { default as TabsDemo } from "./tabs-demo.svelte";
diff --git a/docs/src/lib/components/demos/slider-demo-ticks.svelte b/docs/src/lib/components/demos/slider-demo-ticks.svelte
new file mode 100644
index 000000000..2423f6e55
--- /dev/null
+++ b/docs/src/lib/components/demos/slider-demo-ticks.svelte
@@ -0,0 +1,36 @@
+
+
+
+
+ {#snippet children({ ticks, thumbs })}
+
+
+
+ {#each thumbs as thumb}
+
+ {/each}
+ {#each ticks as tick}
+
+ {/each}
+ {/snippet}
+
+
diff --git a/packages/bits-ui/src/lib/bits/slider/slider.svelte.ts b/packages/bits-ui/src/lib/bits/slider/slider.svelte.ts
index 0623f5458..0bb5c5609 100644
--- a/packages/bits-ui/src/lib/bits/slider/slider.svelte.ts
+++ b/packages/bits-ui/src/lib/bits/slider/slider.svelte.ts
@@ -305,12 +305,9 @@ class SliderSingleRootState extends SliderBaseRootState {
const currValue = this.opts.value.current;
return Array.from({ length: count }, (_, i) => {
- const tickPosition = i * (step / difference) * 100;
+ const tickPosition = i * step;
- const scale = linearScale(
- [this.opts.min.current, this.opts.max.current],
- this.getThumbScale()
- );
+ const scale = linearScale([0, (count - 1) * step], this.getThumbScale());
const isFirst = i === 0;
const isLast = i === count - 1;
@@ -623,12 +620,15 @@ class SliderMultiRootState extends SliderBaseRootState {
const currValue = this.opts.value.current;
return Array.from({ length: count }, (_, i) => {
- const tickPosition = i * (step / difference) * 100;
+ const tickPosition = i * step;
+
+ const scale = linearScale([0, (count - 1) * step], this.getThumbScale());
const isFirst = i === 0;
const isLast = i === count - 1;
const offsetPercentage = isFirst ? 0 : isLast ? -100 : -50;
- const style = getTickStyles(this.direction, tickPosition, offsetPercentage);
+
+ const style = getTickStyles(this.direction, scale(tickPosition), offsetPercentage);
const tickValue = min + i * step;
const bounded =
currValue.length === 1