fix: make sure helpText and label respond to empty strings

This commit is contained in:
Thijs Louisse 2025-07-24 13:25:06 +02:00 committed by Thijs Louisse
parent fb0813bc6d
commit 57eec5b599
3 changed files with 96 additions and 18 deletions

View file

@ -0,0 +1,5 @@
---
'@lion/ui': patch
---
fix: make sure helpText and label respond to empty strings

View file

@ -52,7 +52,7 @@ const FormControlMixinImplementation = superclass =>
* @type {string}
*/
get label() {
return this.__label || (this._labelNode && this._labelNode.textContent) || '';
return this.__label ?? (this._labelNode?.textContent || '');
}
/**
@ -71,7 +71,7 @@ const FormControlMixinImplementation = superclass =>
* @type {string}
*/
get helpText() {
return this.__helpText || (this._helpTextNode && this._helpTextNode.textContent) || '';
return this.__helpText ?? (this._helpTextNode?.textContent || '');
}
/**
@ -158,6 +158,21 @@ const FormControlMixinImplementation = superclass =>
*/
static enabledWarnings = super.enabledWarnings?.filter(w => w !== 'change-in-update') || [];
// N.B. add these label/helpText props for types + ce manifest output
// (explicity setting them to undefined does not have desired result)
/**
* The label text for the input node.
* When no value is defined, textContent of [slot=label] will be used
* @property {string} label
*/
/**
* The helpt text for the input node.
* When no value is defined, textContent of [slot=help-text] will be used
* @property {string} helpText
*/
constructor() {
super();
@ -171,26 +186,12 @@ const FormControlMixinImplementation = superclass =>
*/
this.readOnly = false;
/**
* The label text for the input node.
* When no value is defined, textContent of [slot=label] will be used
* @type {string}
*/
this.label = '';
/**
* The label will only be visible for srceen readers when true
* @type {boolean}
*/
this.labelSrOnly = false;
/**
* The helpt text for the input node.
* When no value is defined, textContent of [slot=help-text] will be used
* @type {string}
*/
this.helpText = '';
/**
* The model value is the result of the parser function(when available).
* It should be considered as the internal value used for validation and reasoning/logic.
@ -293,11 +294,15 @@ const FormControlMixinImplementation = superclass =>
);
}
if (changedProperties.has('label') && this.__label && this._labelNode) {
if (changedProperties.has('label') && this.__label !== undefined && this._labelNode) {
this._labelNode.textContent = this.label;
}
if (changedProperties.has('helpText') && this.__helpText && this._helpTextNode) {
if (
changedProperties.has('helpText') &&
this.__helpText !== undefined &&
this._helpTextNode
) {
this._helpTextNode.textContent = this.helpText;
}

View file

@ -86,6 +86,40 @@ describe('FormControlMixin', () => {
expect(el.label).to.equal('');
});
it('supports empty string as label', async () => {
const el = /** @type {FormControlMixinClass} */ (
await fixture(html`
<${tag} label="With Value">${inputSlot}</${tag}>
`)
);
expect(el.label).to.equal('With Value');
// @ts-expect-error
expect(el._labelNode.innerHTML).to.equal('With Value');
el.label = '';
await el.updateComplete;
expect(el.label).to.equal('');
// @ts-expect-error
expect(el._labelNode.innerHTML).to.equal('');
// Reset
el.label = 'With Value';
await el.updateComplete;
expect(el.label).to.equal('With Value');
// @ts-expect-error
expect(el._labelNode.innerHTML).to.equal('With Value');
el.setAttribute('label', '');
await el.updateComplete;
expect(el.label).to.equal('');
// @ts-expect-error
expect(el._labelNode.innerHTML).to.equal('');
});
/**
* N.B. For platform controls, the same would be achieved with <input aria-label="My label">
* However, since FormControl is usually not the activeElement (_inputNode is), this
@ -176,6 +210,40 @@ describe('FormControlMixin', () => {
);
expect(el.helpText).to.equal('');
});
it('supports empty string as help-text', async () => {
const el = /** @type {FormControlMixinClass} */ (
await fixture(html`
<${tag} help-text="With Value">${inputSlot}</${tag}>
`)
);
expect(el.helpText).to.equal('With Value');
// @ts-expect-error
expect(el._helpTextNode.innerHTML).to.equal('With Value');
el.helpText = '';
await el.updateComplete;
expect(el.helpText).to.equal('');
// @ts-expect-error
expect(el._helpTextNode.innerHTML).to.equal('');
// Reset
el.helpText = 'With Value';
await el.updateComplete;
expect(el.helpText).to.equal('With Value');
// @ts-expect-error
expect(el._helpTextNode.innerHTML).to.equal('With Value');
el.setAttribute('help-text', '');
await el.updateComplete;
expect(el.helpText).to.equal('');
// @ts-expect-error
expect(el._helpTextNode.innerHTML).to.equal('');
});
});
describe('Accessibility', () => {