Environment
Vuetify Version: 4.0.7
Vue Version: 3.5.34
OS: Linux
Steps to reproduce
- Open the playground (Vuetify 4.0.7 + Vue 3.5.34, default config).
- Look at the "Same component rendered through Vue SSR (renderToString)" section.
- Observe the server-rendered HTML:
<div class="v-progress-linear__background" style="opacity:NaN;"></div> and <div class="v-progress-linear__buffer" style="opacity:NaN;width:0%;"></div>.
Expected Behavior
The .v-progress-linear__background and .v-progress-linear__buffer inner divs should resolve their opacity to var(--v-border-opacity), as declared in VProgressLinear.css. No invalid inline opacity value should be emitted.
Actual Behavior
In CSR, Vue assigns each style property to the live HTMLElement; the DOM silently rejects opacity = NaN, so the bug is invisible.
In SSR, Vue serializes the style object via stringifyStyle() from @vue/shared, which accepts any value where typeof === "number" — and typeof NaN === "number". So the server-rendered HTML ships with style="opacity:NaN;" (and "opacity:NaN;width:0%;" for the buffer), which is invalid CSS and is flagged by the W3C validator.
Real-world example: any Nuxt site using Vuetify 4.0.7 with a default (including via Vuetify's own LoaderSlot used by v-text-field / v-data-table / v-btn loading) renders the bug on every SSR response.
Reproduction Link
https://play.vuetifyjs.com/#...
Other comments
Root cause in packages/vuetify/src/components/VProgressLinear/VProgressLinear.tsx: bgOpacity and bufferOpacity are declared as [Number, String] without a default. The inline style is computed via parseFloat(props.bgOpacity!) and parseFloat(props.bufferOpacity!), which yield NaN when the props are undefined (the default case). Likely introduced by #19190 (split of the opacity prop into bgOpacity / bufferOpacity for v3.6). Still present on master at the time of report. Suggested fix: provide explicit numeric defaults matching the SCSS variable (e.g. bgOpacity: 0.12, bufferOpacity: 0.3), or skip the inline opacity style when the prop is undefined so the CSS rule "opacity: var(--v-border-opacity)" keeps applying.
Environment
Vuetify Version: 4.0.7
Vue Version: 3.5.34
OS: Linux
Steps to reproduce
<div class="v-progress-linear__background" style="opacity:NaN;"></div>and<div class="v-progress-linear__buffer" style="opacity:NaN;width:0%;"></div>.Expected Behavior
The
.v-progress-linear__backgroundand.v-progress-linear__bufferinner divs should resolve their opacity to var(--v-border-opacity), as declared in VProgressLinear.css. No invalid inline opacity value should be emitted.Actual Behavior
In CSR, Vue assigns each style property to the live HTMLElement; the DOM silently rejects opacity = NaN, so the bug is invisible.
In SSR, Vue serializes the style object via stringifyStyle() from @vue/shared, which accepts any value where
typeof === "number"— andtypeof NaN === "number". So the server-rendered HTML ships withstyle="opacity:NaN;"(and"opacity:NaN;width:0%;"for the buffer), which is invalid CSS and is flagged by the W3C validator.Real-world example: any Nuxt site using Vuetify 4.0.7 with a default (including via Vuetify's own LoaderSlot used by v-text-field / v-data-table / v-btn loading) renders the bug on every SSR response.
Reproduction Link
https://play.vuetifyjs.com/#...
Other comments
Root cause in packages/vuetify/src/components/VProgressLinear/VProgressLinear.tsx: bgOpacity and bufferOpacity are declared as [Number, String] without a default. The inline style is computed via parseFloat(props.bgOpacity!) and parseFloat(props.bufferOpacity!), which yield NaN when the props are undefined (the default case). Likely introduced by #19190 (split of the opacity prop into bgOpacity / bufferOpacity for v3.6). Still present on master at the time of report. Suggested fix: provide explicit numeric defaults matching the SCSS variable (e.g. bgOpacity: 0.12, bufferOpacity: 0.3), or skip the inline opacity style when the prop is undefined so the CSS rule "opacity: var(--v-border-opacity)" keeps applying.