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} * @type {string}
*/ */
get label() { 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} * @type {string}
*/ */
get helpText() { 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') || []; 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() { constructor() {
super(); super();
@ -171,26 +186,12 @@ const FormControlMixinImplementation = superclass =>
*/ */
this.readOnly = false; 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 * The label will only be visible for srceen readers when true
* @type {boolean} * @type {boolean}
*/ */
this.labelSrOnly = false; 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). * 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. * 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; 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; this._helpTextNode.textContent = this.helpText;
} }

View file

@ -86,6 +86,40 @@ describe('FormControlMixin', () => {
expect(el.label).to.equal(''); 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"> * 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 * However, since FormControl is usually not the activeElement (_inputNode is), this
@ -176,6 +210,40 @@ describe('FormControlMixin', () => {
); );
expect(el.helpText).to.equal(''); 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', () => { describe('Accessibility', () => {