Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 36 additions & 31 deletions core/src/components/checkbox/checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,44 +151,53 @@ export class Checkbox implements ComponentInterface {
connectedCallback() {
const { el } = this;

// Watch for class changes to update validation state.
if (Build.isBrowser && typeof MutationObserver !== 'undefined') {
this.validationObserver = new MutationObserver(() => {
const newIsInvalid = checkInvalidState(el);
if (this.isInvalid !== newIsInvalid) {
this.isInvalid = newIsInvalid;
/**
* Screen readers tend to announce changes
* to `aria-describedby` when the attribute
* is changed during a blur event for a
* native form control.
* However, the announcement can be spotty
* when using a non-native form control
* and `forceUpdate()`.
* This is due to `forceUpdate()` internally
* rescheduling the DOM update to a lower
* priority queue regardless if it's called
* inside a Promise or not, thus causing
* the screen reader to potentially miss the
* change.
* By using a State variable inside a Promise,
* it guarantees a re-render immediately at
* a higher priority.
*/
Promise.resolve().then(() => {
this.hintTextId = this.getHintTextId();
});
this.validationObserver = new MutationObserver((mutations) => {
// Watch for label content changes
if (mutations.some((mutation) => mutation.type === 'characterData')) {
this.hasLabelContent = this.el.textContent !== '';
}
// Watch for class changes to update validation state.
if (mutations.some((mutation) => mutation.type === 'attributes')) {
const newIsInvalid = checkInvalidState(el);
if (this.isInvalid !== newIsInvalid) {
this.isInvalid = newIsInvalid;
/**
* Screen readers tend to announce changes
* to `aria-describedby` when the attribute
* is changed during a blur event for a
* native form control.
* However, the announcement can be spotty
* when using a non-native form control
* and `forceUpdate()`.
* This is due to `forceUpdate()` internally
* rescheduling the DOM update to a lower
* priority queue regardless if it's called
* inside a Promise or not, thus causing
* the screen reader to potentially miss the
* change.
* By using a State variable inside a Promise,
* it guarantees a re-render immediately at
* a higher priority.
*/
Promise.resolve().then(() => {
this.hintTextId = this.getHintTextId();
});
}
}
});

this.validationObserver.observe(el, {
attributes: true,
attributeFilter: ['class'],
characterData: true,
subtree: true,
});
}

// Always set initial state
this.isInvalid = checkInvalidState(el);
this.hasLabelContent = this.el.textContent !== '';
}

componentWillLoad() {
Expand Down Expand Up @@ -267,10 +276,6 @@ export class Checkbox implements ComponentInterface {
ev.stopPropagation();
};

private onSlotChange = () => {
this.hasLabelContent = this.el.textContent !== '';
};

private getHintTextId(): string | undefined {
const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;

Expand Down Expand Up @@ -387,7 +392,7 @@ export class Checkbox implements ComponentInterface {
id={this.inputLabelId}
onClick={this.onDivLabelClick}
>
<slot onSlotchange={this.onSlotChange}></slot>
<slot></slot>
{this.renderHintText()}
</div>
<div class="native-wrapper">
Expand Down
Loading