material-web
material-web copied to clipboard
Add coercing to properties to ensure type safety (`disabled = undefined || null` is not supported)
What is affected?
Component
Description
When I set disabled to undefined on an md-slider, the slider is disabled.
Reproduction
https://lit.dev/playground/#project=W3sibmFtZSI6Im15LWV4YW1wbGUudHMiLCJjb250ZW50IjoiaW1wb3J0IHtodG1sLCBjc3MsIExpdEVsZW1lbnR9IGZyb20gJ2xpdCc7XG5pbXBvcnQge2N1c3RvbUVsZW1lbnR9IGZyb20gJ2xpdC9kZWNvcmF0b3JzLmpzJztcbmltcG9ydCAnQG1hdGVyaWFsL3dlYi9zbGlkZXIvc2xpZGVyJztcblxuQGN1c3RvbUVsZW1lbnQoJ215LWV4YW1wbGUnKVxuZXhwb3J0IGNsYXNzIE15RXhhbXBsZSBleHRlbmRzIExpdEVsZW1lbnQge1xuICBzdGF0aWMgc3R5bGVzID0gY3NzYFxuICAgIGlucHV0IHtcbiAgICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgIH1cbiAgYDtcbiAgXG4gIHJlbmRlcigpIHtcbiAgICByZXR1cm4gaHRtbGBcbiAgICAgIDxtZC1zbGlkZXIgLmRpc2FibGVkPSR7bnVsbH0-PC9tZC1zbGlkZXI-XG4gICAgICA8bWQtc2xpZGVyIC5kaXNhYmxlZD0ke3VuZGVmaW5lZH0-PC9tZC1zbGlkZXI-XG4gICAgICA8aW5wdXQgdHlwZT1cInRleHRcIiAuZGlzYWJsZWQ9JHtudWxsfSAvPlxuICAgICAgPGlucHV0IHR5cGU9XCJ0ZXh0XCIgLmRpc2FibGVkPSR7dW5kZWZpbmVkfSAvPlxuICAgIGA7XG4gIH1cbn1cbiJ9LHsibmFtZSI6ImluZGV4Lmh0bWwiLCJjb250ZW50IjoiPCFET0NUWVBFIGh0bWw-XG48aGVhZD5cbiAgPHNjcmlwdCB0eXBlPVwibW9kdWxlXCIgc3JjPVwiLi9teS1leGFtcGxlLmpzXCI-PC9zY3JpcHQ-XG48L2hlYWQ-XG48Ym9keT5cbiAgPG15LWV4YW1wbGU-PC9teS1leGFtcGxlPlxuPC9ib2R5PlxuIn0seyJuYW1lIjoicGFja2FnZS5qc29uIiwiY29udGVudCI6IntcbiAgXCJkZXBlbmRlbmNpZXNcIjoge1xuICAgIFwibGl0XCI6IFwiXjMuMC4wXCIsXG4gICAgXCJAbGl0L3JlYWN0aXZlLWVsZW1lbnRcIjogXCJeMi4wLjBcIixcbiAgICBcImxpdC1lbGVtZW50XCI6IFwiXjQuMC4wXCIsXG4gICAgXCJsaXQtaHRtbFwiOiBcIl4zLjAuMFwiXG4gIH1cbn0iLCJoaWRkZW4iOnRydWV9XQ
Workaround
Set disabled to null instead of undefined to disable a slider.
Is this a regression?
Yes. This used to work, but now it doesn't.
Affected versions
1.1.1
Browser/OS/Node environment
Browser: Firefox 121.0 OS: macOS 14.2
It looks like this was introduced in 2234a1279fb945f038cc29bfe1bba073bffe2252 and possibly affects more than just sliders.
I think it's a code issue? Your code renders this HTML so it's correctly disabled:
Removing the attribute correctly enables it: Lit Playground
The issue is that rendering with .disabled=${undefined} (incorrectly) disables the field. The native HTML input element treats undefined the same as false when setting "disabled", as did @material/web up until 1.1.1. I don't think setting disabled to undefined should disable the field.
Seems like the behaviour was actually changed in v1.1.0.
Here's a playground using 1.0.1
Note that the second slider is enabled in 1.0.1 but not 1.1.0.
Overall this is related to coercing property values.
We do not coerce at runtime and expect type adherence, so setting slider.disabled = undefined may result in type issues where we expect an explicit boolean.
As a workaround, we recommend using typescript and lit-analyzer to ensure type safety, then ensuring default types where the types do not match. For example:
<md-slider .disabled=${this.disabledOrNull ?? false}>
Coercing would be a good feature to add though (updated the title).
slider.disabled = null;
console.log(slider.disabled); // `false` expected
This would help with edge cases where type safety is not guaranteed, such as removing attributes with Lit's default boolean attribute converter.
We can use our own attribute converters and/or decorators to provide some default coercing features that match platform expectations for coercing.