diff --git a/docs/components/form.md b/docs/components/form.md index d4415c28a..dd7a3a3a1 100644 --- a/docs/components/form.md +++ b/docs/components/form.md @@ -75,8 +75,6 @@ When a form control is invalid, the containing form will not be submitted. Inste All form controls support validation, but not all validation props are available for every component. Refer to a component's documentation to see which validation props it supports. -Note that validity is not checked until the user interacts with the control or its containing form is submitted. This prevents required controls from being rendered as invalid right away, which can result in a poor user experience. If you need this behavior, set the `invalid` attribute initially. - !> Client-side validation can be used to improve the UX of forms, but it is not a replacement for server-side validation. **You should always validate and sanitize user input on the server!** ### Required Fields diff --git a/docs/resources/changelog.md b/docs/resources/changelog.md index 2961ef4eb..5d0f45b91 100644 --- a/docs/resources/changelog.md +++ b/docs/resources/changelog.md @@ -8,12 +8,15 @@ _During the beta period, these restrictions may be relaxed in the event of a mis ## Next +- 🚨 BREAKING: all `invalid` props on form controls now reflect validity before interaction [#455](https://github.com/shoelace-style/shoelace/issues/455) - Allow `null` to be passed to disable animations in `setDefaultAnimation()` and `setAnimation()` +- Fixed a bug in `sl-checkbox` where `invalid` did not update properly - Fixed a bug in `sl-dropdown` where a `keydown` listener wasn't cleaned up properly - Fixed a bug in `sl-select` where `sl-blur` was emitted prematurely [#456](https://github.com/shoelace-style/shoelace/issues/456) - Fixed a bug in `sl-select` where no selection with `multiple` resulted in an incorrect value [#457](https://github.com/shoelace-style/shoelace/issues/457) - Fixed a bug in `sl-select` where `sl-change` was emitted immediately after connecting to the DOM [#458](https://github.com/shoelace-style/shoelace/issues/458) - Fixed a bug in `sl-select` where non-printable keys would cause the menu to open +- Fixed a bug in `sl-select` where `invalid` was not always updated properly - Reworked the `@watch` decorator to use `update` instead of `updated` resulting in better performance and flexibility ## 2.0.0-beta.43 diff --git a/src/components/checkbox/checkbox.ts b/src/components/checkbox/checkbox.ts index 3fdf99fc4..aee63f618 100644 --- a/src/components/checkbox/checkbox.ts +++ b/src/components/checkbox/checkbox.ts @@ -62,6 +62,7 @@ export default class SlCheckbox extends LitElement { firstUpdated() { this.input.indeterminate = this.indeterminate; + this.invalid = !this.input.checkValidity(); } /** Simulates a click on the checkbox. */ @@ -116,6 +117,7 @@ export default class SlCheckbox extends LitElement { handleStateChange() { this.input.checked = this.checked; this.input.indeterminate = this.indeterminate; + this.invalid = !this.input.checkValidity(); this.slChange.emit(); } diff --git a/src/components/input/input.ts b/src/components/input/input.ts index 2647ae7d0..42333a40d 100644 --- a/src/components/input/input.ts +++ b/src/components/input/input.ts @@ -152,6 +152,10 @@ export default class SlInput extends LitElement { this.shadowRoot!.addEventListener('slotchange', this.handleSlotChange); } + firstUpdated() { + this.invalid = !this.input.checkValidity(); + } + disconnectedCallback() { super.disconnectedCallback(); this.shadowRoot!.removeEventListener('slotchange', this.handleSlotChange); diff --git a/src/components/select/select.ts b/src/components/select/select.ts index 76348622f..c690af64d 100644 --- a/src/components/select/select.ts +++ b/src/components/select/select.ts @@ -133,6 +133,10 @@ export default class SlSelect extends LitElement { }); } + firstUpdated() { + this.invalid = !this.input.checkValidity(); + } + disconnectedCallback() { super.disconnectedCallback(); this.resizeObserver.unobserve(this); @@ -313,8 +317,10 @@ export default class SlSelect extends LitElement { } @watch('value', { waitUntilFirstUpdate: true }) - handleValueChange() { + async handleValueChange() { this.syncItemsFromValue(); + await this.updateComplete; + this.invalid = !this.input.checkValidity(); this.slChange.emit(); } diff --git a/src/components/switch/switch.ts b/src/components/switch/switch.ts index 6ed767e9b..494530530 100644 --- a/src/components/switch/switch.ts +++ b/src/components/switch/switch.ts @@ -60,6 +60,10 @@ export default class SlSwitch extends LitElement { /** Emitted when the control gains focus. */ @event('sl-focus') slFocus: EventEmitter; + firstUpdated() { + this.invalid = !this.input.checkValidity(); + } + /** Simulates a click on the switch. */ click() { this.input.click(); @@ -122,6 +126,7 @@ export default class SlSwitch extends LitElement { handleCheckedChange() { if (this.input) { this.input.checked = this.checked; + this.invalid = !this.input.checkValidity(); this.slChange.emit(); } } diff --git a/src/components/textarea/textarea.ts b/src/components/textarea/textarea.ts index ad6540ebe..bcef8fe3f 100644 --- a/src/components/textarea/textarea.ts +++ b/src/components/textarea/textarea.ts @@ -140,6 +140,10 @@ export default class SlTextarea extends LitElement { }); } + firstUpdated() { + this.invalid = !this.input.checkValidity(); + } + disconnectedCallback() { super.disconnectedCallback(); this.resizeObserver.unobserve(this.input);