diff --git a/packages/form-core/src/FormControlMixin.js b/packages/form-core/src/FormControlMixin.js
index 21eb8b63a..7b5d18311 100644
--- a/packages/form-core/src/FormControlMixin.js
+++ b/packages/form-core/src/FormControlMixin.js
@@ -43,6 +43,7 @@ const FormControlMixinImplementation = superclass =>
name: { type: String, reflect: true },
readOnly: { type: Boolean, attribute: 'readonly', reflect: true },
label: String, // FIXME: { attribute: false } breaks a bunch of tests, but shouldn't...
+ labelSrOnly: { type: Boolean, attribute: 'label-sr-only', reflect: true },
helpText: { type: String, attribute: 'help-text' },
modelValue: { attribute: false },
_ariaLabelledNodes: { attribute: false },
@@ -186,6 +187,12 @@ const FormControlMixinImplementation = superclass =>
*/
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
@@ -699,6 +706,20 @@ const FormControlMixinImplementation = superclass =>
color: var(--disabled-text-color, #767676);
}
+ :host([label-sr-only]) .form-field__label {
+ position: absolute;
+ top: 0;
+ width: 1px;
+ height: 1px;
+ overflow: hidden;
+ clip-path: inset(100%);
+ clip: rect(1px, 1px, 1px, 1px);
+ white-space: nowrap;
+ border: 0;
+ margin: 0;
+ padding: 0;
+ }
+
/***********************
{block} .input-group
*********************/
diff --git a/packages/form-core/test/FormControlMixin.test.js b/packages/form-core/test/FormControlMixin.test.js
index bbc5e373b..df18d36b8 100644
--- a/packages/form-core/test/FormControlMixin.test.js
+++ b/packages/form-core/test/FormControlMixin.test.js
@@ -80,6 +80,43 @@ describe('FormControlMixin', () => {
expect(el.label).to.equal('');
});
+ /**
+ * N.B. For platform controls, the same would be achieved with
+ * However, since FormControl is usually not the activeElement (_inputNode is), this
+ * will not have the desired effect on for instance lion-input
+ */
+ it('supports "label-sr-only" to make label visually hidden, but accessible for screen reader users', async () => {
+ const el = /** @type {FormControlMixinClass} */ (
+ await fixture(html`
+ <${tag} label-sr-only>
+
+ ${inputSlot}
+ ${tag}>`)
+ );
+
+ const expectedValues = {
+ position: 'absolute',
+ top: '0px',
+ width: '1px',
+ height: '1px',
+ overflow: 'hidden',
+ clipPath: 'inset(100%)',
+ clip: 'rect(1px, 1px, 1px, 1px)',
+ whiteSpace: 'nowrap',
+ borderWidth: '0px',
+ margin: '0px',
+ padding: '0px',
+ };
+
+ const labelStyle = window.getComputedStyle(
+ // @ts-ignore
+ el.shadowRoot?.querySelector('.form-field__label'),
+ );
+ Object.entries(expectedValues).forEach(([key, val]) => {
+ expect(labelStyle[key]).to.equal(val);
+ });
+ });
+
it('can have a help-text', async () => {
const elAttr = /** @type {FormControlMixinClass} */ (
await fixture(html`