diff --git a/src/material/slider/_m3-slider.scss b/src/material/slider/_m3-slider.scss
index c3e4908fb560..094d96a072bd 100644
--- a/src/material/slider/_m3-slider.scss
+++ b/src/material/slider/_m3-slider.scss
@@ -20,13 +20,13 @@
slider-inactive-track-shape: map.get($system, corner-full),
slider-with-tick-marks-container-shape: map.get($system, corner-full),
slider-value-indicator-opacity: 1,
- slider-value-indicator-padding: 0,
- slider-value-indicator-width: $indicator-size,
+ slider-value-indicator-padding: 0 12px,
+ slider-value-indicator-width: auto,
slider-value-indicator-height: $indicator-size,
slider-value-indicator-caret-display: none,
- slider-value-indicator-border-radius: 50% 50% 50% 0,
- slider-value-indicator-text-transform: rotate(45deg),
- slider-value-indicator-container-transform: translateX(-50%) rotate(-45deg),
+ slider-value-indicator-border-radius: map.get($system, corner-full),
+ slider-value-indicator-text-transform: none,
+ slider-value-indicator-container-transform: translateX(-50%),
slider-active-track-height: 4px,
slider-handle-height: 20px,
slider-handle-width: 20px,
@@ -35,7 +35,7 @@
slider-with-tick-marks-active-container-opacity: 0.38,
slider-with-tick-marks-container-size: 2px,
slider-with-tick-marks-inactive-container-opacity: 0.38,
- slider-value-indicator-transform-origin: 0 $indicator-size,
+ slider-value-indicator-transform-origin: bottom,
),
color: (
slider-active-track-color: map.get($system, primary),
diff --git a/src/material/slider/slider.scss b/src/material/slider/slider.scss
index 952f722af0c2..c2b73b52adf1 100644
--- a/src/material/slider/slider.scss
+++ b/src/material/slider/slider.scss
@@ -160,6 +160,7 @@ $fallbacks: m3-slider.get-tokens();
.mdc-slider__value-indicator-text {
text-align: center;
+ white-space: nowrap;
width: token-utils.slot(slider-value-indicator-width, $fallbacks);
transform: token-utils.slot(slider-value-indicator-text-transform, $fallbacks);
font-family: token-utils.slot(slider-label-label-text-font, $fallbacks);
diff --git a/src/material/slider/slider.spec.ts b/src/material/slider/slider.spec.ts
index a22860c4ae78..6caeb0964ce1 100644
--- a/src/material/slider/slider.spec.ts
+++ b/src/material/slider/slider.spec.ts
@@ -1044,6 +1044,78 @@ describe('MatSlider', () => {
});
});
+ describe('long value indicators', () => {
+ for (const range of [false, true]) {
+ for (const direction of ['ltr', 'rtl'] as const) {
+ it(`should fit and center long labels (range: ${range}, direction: ${direction})`, () => {
+ const component = range
+ ? DiscreteRangeSliderWithDisplayWith
+ : DiscreteSliderWithDisplayWith;
+ const fixture = createComponent(component, [provideFakeDirectionality(direction)]);
+ fixture.nativeElement.dir = direction;
+ fixture.componentInstance.displayWith = () => '1';
+ fixture.detectChanges();
+ const slider: MatSlider = fixture.debugElement.query(
+ By.directive(MatSlider),
+ ).componentInstance;
+
+ const thumbs: HTMLElement[] = Array.from(
+ fixture.nativeElement.querySelectorAll('.mdc-slider__thumb'),
+ );
+
+ for (const thumb of thumbs) {
+ thumb.classList.add('mdc-slider__thumb--with-indicator');
+ // Measure the final layout without waiting for the entrance animation.
+ thumb.querySelector('.mdc-slider__value-indicator')!.style.transition =
+ 'none';
+ }
+
+ const initialRect = thumbs[0]
+ .querySelector('.mdc-slider__value-indicator')!
+ .getBoundingClientRect();
+
+ for (const label of ['2026', '10000', 'September 2026', '1']) {
+ fixture.componentInstance.displayWith = () => label;
+ fixture.changeDetectorRef.markForCheck();
+ fixture.detectChanges();
+ for (const position of [_MatThumb.START, _MatThumb.END]) {
+ const input = slider._getInput(position) as MatSliderThumb | undefined;
+ if (input) {
+ input.value = input.value === 200 ? 199 : input.value + 1;
+ }
+ }
+ fixture.detectChanges();
+
+ for (const thumb of thumbs) {
+ const indicator = thumb.querySelector('.mdc-slider__value-indicator')!;
+ const text = thumb.querySelector('.mdc-slider__value-indicator-text')!;
+ const textRange = document.createRange();
+ textRange.selectNodeContents(text);
+
+ const indicatorRect = indicator.getBoundingClientRect();
+ const textRect = textRange.getBoundingClientRect();
+ const thumbRect = thumb.getBoundingClientRect();
+
+ expect(text.textContent).toBe(label);
+ expect(textRect.left).withContext(label).toBeGreaterThan(indicatorRect.left);
+ expect(textRect.right).withContext(label).toBeLessThan(indicatorRect.right);
+ expect(textRect.height).withContext(label).toBeLessThan(indicatorRect.height);
+ expect(indicatorRect.height).withContext(label).toBeCloseTo(initialRect.height, 0);
+ if (label === '1') {
+ expect(indicatorRect.width).toBeCloseTo(initialRect.width, 0);
+ } else {
+ expect(indicatorRect.width).withContext(label).toBeGreaterThan(initialRect.width);
+ }
+ expect(indicatorRect.left + indicatorRect.width / 2)
+ .withContext(label)
+ .toBeCloseTo(thumbRect.left + thumbRect.width / 2, 0);
+ }
+ }
+ });
+ }
+ }
+ });
+
describe('slider with value property binding', () => {
let fixture: ComponentFixture;
let input: MatSliderThumb;