Repository navigation
fix(react-slider): stop emitting the deprecated slider-vertical appearance - #36946
Jake Salvesen (jakesalvesen) wants to merge 7 commits into
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Removing the fallback breaks vertical interaction in older browsers still covered by the published support matrix.
1 open issue
What changed in this PR
Removes deprecated vertical Slider CSS to address Chromium warnings reported in #36945, following #34022.
Changes:
- Applies standardized vertical input styles directly and removes the legacy fallback.
- Adds a patch release change file for
@fluentui/react-slider.
| File | Description |
|---|---|
| packages/react-components/react-slider/library/src/components/Slider/useSliderStyles.styles.ts | Replaces conditional appearance rules with standardized vertical styles. |
| change/change-@fluentui-react-slider-b43fe38a-5da5-412c-a9f6-692ebb39bb92.json | Records the Slider fix for release. |
Review effort: Balanced
14120c0 to
3cf0e46
Compare
Paul Mardling (PaulGMardling)
left a comment
There was a problem hiding this comment.
Thanks for working through the compatibility fixes—the vertical-only selector and nonce handling address those concerns. There’s one remaining issue with the capability probe: global input sizing can make a supporting browser appear unsupported and bring the deprecation warning back. Could we isolate the probe from application styles and cover that case before merging?
Paul Mardling (PaulGMardling)
left a comment
There was a problem hiding this comment.
The earlier fixes look good. I found two more issues with CSP and stylesheet detection—details in the inline comments. Could we sort those out before merging?
Paul Mardling (PaulGMardling)
left a comment
There was a problem hiding this comment.
Looks good now—the issues I raised are addressed. Thanks for sticking with the fixes and adding the regression tests. Happy to approve!
|
Thank you so much, Paul Mardling (@PaulGMardling). I really appreciate the time and care you put into these reviews. Every round caught something real: application input sizing, range pseudo-elements, shadow roots, hidden mounts, then CSP and stylesheet detection. The Slider is much more robust for it, and the regression tests will keep it that way. Since you confirmed everything is addressed, I've resolved the remaining conversations. Two small things, in case they're useful. The CI, Check packages, Bundle size and VRT workflows are waiting for maintainer approval to run on this fork (they show "action required"). The PR also still needs a code-owner review from @microsoft/fluentui-react-build, because the Cypress setup adds |
043c669 to
41b8f06
Compare
📊 Bundle size reportUnchanged fixtures
|
|
Pull request demo site: URL |
|
Thank you for updating the branch and starting CI, Paul Mardling (@PaulGMardling)! The
Both specs pass locally on React 17 (Electron 118), 18 and 19 (Electron 130). Sorry for the extra round, and thanks again for your patience. |
|
[P2] RTL vertical sliders reverse native interaction on Chromium 124–131 Affected: Render The paranoid reviewer verified exact base/head Slider sources in Chromium 130.0.6723.137 / Electron 33.2.1, where
LTR passed; RTL failed with Please prevent RTL auto-flipping here, e.g. Verification: isolated scratch Nx target: node node_modules/nx/bin/nx.js run review:component --outputStyle=streamLimitations: this used pinned Slider sources with installed dependencies, supplying the missing |
|
Thank you for the careful review and the clear repro, Tudor Popa (@tudorpopams). You're right. I reproduced it with a new Cypress spec,
LTR passes in every case. So this PR extended an existing problem to 124–131: on master, RTL was already reversed wherever the Fixed in 5c481d7 with Thanks again for catching this! |
🕵 . No visual changes in this PR |
…rance Slider vertical still logs the Chromium deprecation for the non-standard -webkit-appearance: slider-vertical value, even though the browser renders the slider with writing-mode: vertical-lr. microsoft#34022 moved the value into an @supports not (writing-mode: sideways-lr) branch, which is right for browsers without that feature. Chromium 132 added sideways-lr, so the branch is now dead there, but Chromium still reports the deprecated value while parsing the CSS - the warning is emitted even when the condition does not match and when the selector matches no element, including rules inserted at runtime by Griffel. Use the standardized declarations unconditionally. Vertically oriented form controls support writing-mode since Chrome 124, Firefox 120 and Safari 17.4, so every browser that previously took the fallback now gets the same rendering through writing-mode, and browsers older than that lose the legacy native vertical appearance - which the removal of the keyword forces eventually anyway.
Chromium reports the deprecated `-webkit-appearance: slider-vertical` value while parsing a stylesheet, so the fallback cannot live in the Slider styles even inside an `@supports not (...)` branch that never matches. `useSlider_unstable` now installs it from an effect, only for vertical sliders, in engines where a layout probe shows range inputs do not follow `writing-mode`. The rule is scoped to `[orient="vertical"]` because the legacy value also turns horizontal inputs vertical, the style element carries the Griffel renderer attributes so a CSP nonce applies, an inconclusive probe (no layout) installs nothing, and each document is probed once. Server rendering is unaffected and markup never changes, so hydration cannot mismatch.
A global rule such as `input { width: 100% }` resized the probe, so a browser that orients range inputs measured as
horizontal, installed the deprecated `slider-vertical` rule and brought the warning back for the whole document.
The probe now resets every author declaration with `all: initial !important` and is measured with
`offsetWidth`/`offsetHeight`, which report the layout box before transforms, so neither global input sizing nor a
transformed ancestor can change the reading.
Adds Cypress component tests that measure the probe in a real layout engine under several global styles, including the
reported `input { width: 100% }` case, and mount a vertical Slider under those styles.
…try hidden mounts - Insert the fallback into the root the Slider renders in: a shadow root (as with createShadowDOMRenderer) gets a constructed sheet, otherwise the document head gets a style element. Each root is deduplicated by what it already contains, so a removed rule is restored and a second copy of the package does not add it again. - When the probe is inconclusive (no layout, e.g. a display: none iframe), watch the input and decide once it is laid out, so revealing it is enough without any prop change. - Measure the probe inside its own shadow root, so application styles on range pseudo-elements (::-webkit-slider-runnable-track, ::-webkit-slider-thumb) cannot skew it, and restore the native appearance with every spelling after all: initial. - Fall back to the document when the rendered input is not reachable through a ref. Adds Cypress coverage for the createShadowDOMRenderer setup, mounting while hidden and revealing, and track/thumb pseudo-element styles, plus Jest coverage for per-root dedupe, restore after removal, cross-copy dedupe and a document without a head.
…ed sheets and ref wrapping - Apply the capability probe's host and input styles through CSSOM (`style.cssText`) instead of the `style` attribute, which a nonce-only `style-src` or `style-src-attr 'none'` blocks. - Recognise an existing fallback only by its selector and declaration, so an unrelated adopted `slider-vertical` sheet no longer suppresses the Slider rule. - Skip installing where the engine cannot parse the value, checked once per window and only after the root is found not to carry the rule, since Chromium also reports the deprecation for that query. - Locate the styling root from the Slider root element, which the base hook already composes, so the input ref is passed through unwrapped and keeps React 19 ref cleanup. - Regenerate the API report for the value import of React added earlier. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…s without vertical range support - Render through `mount` and a portal into the iframe or shadow root instead of `createRoot` from `react-dom/client`, which does not exist in React 17. - Take the expected vertical range support from the browser version: the React 17 run uses Cypress 13 with Electron 118 (Chromium 118), which needs the fallback, while React 18 and 19 run on a Chromium with native support. - Force a legacy probe reading instead of swapping the probe axes, so the simulation reads as legacy on every engine. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Under an RTL provider Griffel flips `direction: 'rtl'` to `ltr`, which reverses the native vertical range input: the top sets the minimum and ArrowUp decreases the value. On master this already affected engines that take the `writing-mode` path (Chromium 132+); this PR moved Chromium 124-131 onto that path as well. - Mark the declaration `/* @NoFlip */`, as in `useRangeSliderStyles.styles.ts`. - Add `Slider.cy.tsx`, which clicks the top and bottom of a vertical Slider and presses ArrowUp/ArrowDown with real events, in LTR and RTL. - Mention RTL in the change file. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
831c085 to
6052497
Compare


Previous Behavior
Slider verticallogged the Chromium deprecation warning for the non-standard-webkit-appearance: slider-verticalvalue in every app that mounts a vertical slider:#34022 moved the value into an
@supports not (writing-mode: sideways-lr)branch, which is right for browsers that lacksideways-lr. Chromium 132 shippedsideways-lr, so in current Chromium that branch never matches and the vertical slider is styled by the@supports (writing-mode: sideways-lr)branch. The deprecated declaration is dead in those browsers, but Chromium reports deprecated CSS values while parsing: the warning fires even when the condition does not match, when the selector matches no element, and when the rule is inserted at runtime throughCSSStyleSheet.insertRule, which is how Griffel inserts styles.New Behavior
verticaluses the standardized declarations directly:The deprecated value is no longer emitted with the stylesheet. Engines that cannot orient a range input with
writing-modeget it at runtime instead, from auseEffectinuseSlider_unstablethat runs only for vertical sliders and callsensureLegacyVerticalSliderInput(input, renderer.styleElementAttributes)with the rendered input element.Detection.
legacyVerticalSliderAppearance.tsmeasures an off-screen<input type="range">withwriting-mode: vertical-lr; direction: rtl, rendered inside a shadow root of its own so no application selector reaches it or its range pseudo-elements, and comparesoffsetWidth/offsetHeight(pre-transform). A range input that followswriting-modeswaps its axes. This is a layout probe rather thanCSS.supports('writing-mode', 'sideways-lr')because the two features shipped separately: Chrome 124-131 and Safari 17.4-18.3 orient range inputs but do not supportsideways-lr. A conclusive result is cached per document.The rule, added only when the probe says the engine cannot orient range inputs:
It is scoped to
[orient="vertical"]because in those engines the value also turns a horizontal range input vertical.Where it goes. Into the styling root the Slider renders in: a shadow root (as with
createShadowDOMRenderer) adopts a constructed sheet, or gets a<style>when constructed sheets are unavailable; otherwise the document head gets a<style>carrying the Griffel renderer'sstyleElementAttributes, so a CSPnonceset on a DOM renderer applies. Each root is deduplicated by what it already contains, so a removed rule is restored and a second copy of the package does not add it again. If the rendered input is not reachable through a ref, the provider'stargetDocumentis used.When it is decided. If the document has no layout yet (for example a Slider mounted in a
display: noneiframe), the probe is inconclusive and nothing is installed on a guess; aResizeObserveron the input decides once it is laid out, so revealing it is enough with no prop change. The observer is disconnected on a decision or on unmount.RTL.
directionis marked/* @noflip */, as inuseRangeSliderStyles.styles.ts. Without it, Griffel flips the value toltrunder an RTL provider, which reverses the native input: the top sets the minimum and ArrowUp decreases the value. On master that already happened wherever the@supports (writing-mode: sideways-lr)branch applies (verified in Chrome 156), and without the marker this PR would have extended it to Chromium 124-131.Resulting behavior:
writing-modebranch before this change (it supportssideways-lrsince 43), and-webkit-appearance: slider-verticalis not a Gecko value, so its behavior there is unchanged by this PR.Slidersnapshots keep semantic class names (fui-Slider__input) and no markup changes, so no snapshot needs regeneration.Validation
CSS.supports('writing-mode', 'sideways-lr')istrueand the rule never applies. The repro page in [Bug]: Vertical Slider still logs the deprecated 'slider-vertical' warning in Chromium 132+ #36945 shows this side by side.FormControlsVerticalWritingModeSupportdisabled, Firefox 157, WebKit) under application styles includinginput { width: 100% },!importantinput sizing,::-webkit-slider-runnable-trackand::-webkit-slider-thumbsizing,appearance: none !important, an RTL verticalhtml, and a rotated and zoomedbody: 40/40 correct, with nothing installed on supporting engines.legacyVerticalSliderAppearance.cy.tsx,legacyVerticalSliderAppearance.shadowDom.cy.tsx, using the samecypress.config.ts/tsconfig.cy.jsonsetup asreact-color-picker): probe isolation under global input and range pseudo-element styles, a verticalSliderunder all of them, thecreateShadowDOMRenderersetup, and a Slider mounted in adisplay: noneiframe and then revealed. Each review case fails against the code before its fix.Slider.cy.tsxclicks the top and bottom of a vertical Slider's input and presses ArrowUp/ArrowDown with real events, in LTR and RTL. RTL fails on master in Chrome 156 and on this branch without@noflipin Electron 130 and Chrome 156, and passes with it.legacyVerticalSliderAppearance.test.ts) covers the probe, per-root installation and dedupe, restore after removal, cross-copy dedupe, a document without a head, the document fallback, the CSP attributes, and the inconclusive retry and its cleanup.nx run-many -t test,type-check,lint -p react-sliderpasses (69 tests, 3 snapshots), andcypress run --componentpasses 20/20 on React 19 (Electron 130 and Chrome 156) and in the React 17 (Electron 118) and React 18 (Electron 130) integration projects. The changed files passprettier --check.Related Issue(s)