diff --git a/.changeset/cruel-eels-open.md b/.changeset/cruel-eels-open.md
new file mode 100644
index 00000000000..1a262f4e355
--- /dev/null
+++ b/.changeset/cruel-eels-open.md
@@ -0,0 +1,5 @@
+---
+'@spectrum-web-components/menu': minor
+---
+
+**Fixed** MenuItem focus stealing from input elements on mouseover by enhanceing MenuItem's `handleMouseover` method to detect when an input element currently has focus and prevent stealing focus in those cases.
diff --git a/packages/color-field/README.md b/packages/color-field/README.md
index 52dcb6dee14..b5b38585431 100644
--- a/packages/color-field/README.md
+++ b/packages/color-field/README.md
@@ -33,7 +33,7 @@ The color field consists of several key parts:
- **Size variations**: Different size options to match your design requirements
```html
-
+Background color
```
### Options
@@ -45,7 +45,11 @@ The color field consists of several key parts:
```html
-
+
```
@@ -53,7 +57,11 @@ The color field consists of several key parts:
```html
-
+
```
@@ -62,7 +70,11 @@ The color field consists of several key parts:
```html
-
+
```
@@ -71,7 +83,11 @@ The color field consists of several key parts:
```html
-
+
```
@@ -82,7 +98,7 @@ The color field consists of several key parts:
When `view-color` is true, the color handle will be rendered. This is useful for development and debugging purposes.
```html
-
+Icon color
```
#### Quiet
@@ -90,7 +106,7 @@ When `view-color` is true, the color handle will be rendered. This is useful for
A quiet color field provides a more subtle appearance:
```html
-
+Icon color
```
### States
@@ -100,7 +116,7 @@ A quiet color field provides a more subtle appearance:
The default state of the color field, ready for user input:
```html
-
+Icon color
```
#### Read Only
@@ -108,7 +124,7 @@ The default state of the color field, ready for user input:
A readonly color field that displays the color value but prevents user modification:
```html
-
+Icon color
```
#### Invalid Input
@@ -116,7 +132,7 @@ A readonly color field that displays the color value but prevents user modificat
If the input value is not a valid color, `` will not accept it and may show validation feedback:
```html
-
+Icon color
```
### Behaviors
@@ -134,7 +150,7 @@ For a complete list of supported color formats, see the [ColorController documen
A hexadecimal color is specified with: `#RRGGBB`. `RR` (red), `GG` (green) and `BB` (blue) are hexadecimal integers between `00` and `FF` specifying the intensity of the color.
```html
-
+
```
@@ -144,7 +160,7 @@ A hexadecimal color is specified with: `#RRGGBB`. `RR` (red), `GG` (green) and `
Shorthand hexadecimal color values are also supported. `#RGB` is a shorthand for `#RRGGBB`. In the shorthand form, `R` (red), `G` (green), and `B` (blue) are hexadecimal characters between `0` and `F`. Each character is repeated to create the full 6-digit color code. For example, `#123` would expand to `#112233`.
```html
-
+
```
@@ -154,7 +170,11 @@ Shorthand hexadecimal color values are also supported. `#RGB` is a shorthand for
An RGB color value is specified with: rgb(red, green, blue). Each parameter defines the intensity of the color with a value between 0 and 255.
```html
-
+
```
@@ -164,7 +184,11 @@ An RGB color value is specified with: rgb(red, green, blue). Each parameter defi
An RGBA color value is specified with: `rgba(red, green, blue, alpha)`. The `alpha` parameter is a number between 0.0 (fully transparent) and 1.0 (fully opaque).
```html
-
+
```
@@ -174,7 +198,11 @@ An RGBA color value is specified with: `rgba(red, green, blue, alpha)`. The `alp
An HSL color value is specified with: hsl(hue, saturation, lightness). Hue is a degree on the color wheel from 0 to 360. 0 is red, 120 is green, and 240 is blue. Saturation and lightness are percentages.
```html
-
+
```
@@ -184,7 +212,11 @@ An HSL color value is specified with: hsl(hue, saturation, lightness). Hue is a
An HSV color value is specified with: hsv(hue, saturation, value). Hue is a degree on the color wheel from 0 to 360. 0 is red, 120 is green, and 240 is blue. Saturation and value are percentages.
```html
-
+
```
diff --git a/packages/color-field/stories/color-field-sizes.stories.ts b/packages/color-field/stories/color-field-sizes.stories.ts
index ec408601a77..9d514700963 100644
--- a/packages/color-field/stories/color-field-sizes.stories.ts
+++ b/packages/color-field/stories/color-field-sizes.stories.ts
@@ -10,8 +10,6 @@
* governing permissions and limitations under the License.
*/
import { TemplateResult } from '@spectrum-web-components/base';
-
-import '@spectrum-web-components/field-label/sp-field-label.js';
import '@spectrum-web-components/help-text/sp-help-text.js';
import { ColorFieldMarkup } from './template.js';
diff --git a/packages/combobox/README.md b/packages/combobox/README.md
index 4b2dee37ca0..1e75902da0b 100644
--- a/packages/combobox/README.md
+++ b/packages/combobox/README.md
@@ -120,8 +120,8 @@ mutate() {
### Quiet
```html
-Color
-
+
+ ColorRedGreenBlue
@@ -140,8 +140,8 @@ The suggested popup menu items will remain the same regardless of the currently-
Whenever the currently-typed input exactly matches the `value` of a popup menu item, that item is automatically selected.
```html
-Color
-
+
+ ColorRedGreenBlue
@@ -155,8 +155,8 @@ Whenever the currently-typed input exactly matches the `value` of a popup menu i
The popup menu items are filtered to only those completing the currently-input value.
```html
-Color
-
+
+ ColorRedGreenBlue
@@ -170,15 +170,15 @@ The popup menu items are filtered to only those completing the currently-input v
```html
-Color
-
+
+ ColorRedGreenBlue
-Color
-
+
+ ColorRedGreenBlue
@@ -190,8 +190,8 @@ The popup menu items are filtered to only those completing the currently-input v
```html
-Color
-
+
+ ColorRedGreenBlue
@@ -206,8 +206,8 @@ The popup menu items are filtered to only those completing the currently-input v
```html
-Color
-
+
+ ColorRedGreenBlue
@@ -222,12 +222,12 @@ The popup menu items are filtered to only those completing the currently-input v
#### Provide a label
A combobox must be labeled.
-Typically, you should render a visible label via ``.
+Typically, you should render a visible label via the `label` slot.
For exceptional cases, provide an accessible label via the `label` attribute.
```html
-Color
-
+
+ ColorRedGreenBlue
@@ -245,8 +245,8 @@ See [help text](../help-text) and [tooltip](../tooltip) for more information.
```html
-Color
-
+
+ ColorRedGreenBlue
@@ -259,8 +259,8 @@ See [help text](../help-text) and [tooltip](../tooltip) for more information.
```html
-Color
-
+
+ ColorRedGreenBlue
@@ -274,8 +274,8 @@ See [help text](../help-text) and [tooltip](../tooltip) for more information.
```html
-Color
-
+
+ Color
Color options, such as red, green, or blue.
diff --git a/packages/combobox/package.json b/packages/combobox/package.json
index 6be53918fe4..89720c27699 100644
--- a/packages/combobox/package.json
+++ b/packages/combobox/package.json
@@ -66,6 +66,7 @@
"dependencies": {
"@spectrum-web-components/action-button": "1.9.0",
"@spectrum-web-components/base": "1.9.0",
+ "@spectrum-web-components/field-label": "1.9.0",
"@spectrum-web-components/icon": "1.9.0",
"@spectrum-web-components/icons-ui": "1.9.0",
"@spectrum-web-components/menu": "1.9.0",
@@ -74,6 +75,7 @@
"@spectrum-web-components/popover": "1.9.0",
"@spectrum-web-components/progress-circle": "1.9.0",
"@spectrum-web-components/reactive-controllers": "1.9.0",
+ "@spectrum-web-components/shared": "1.9.0",
"@spectrum-web-components/textfield": "1.9.0"
},
"types": "./src/index.d.ts",
diff --git a/packages/combobox/src/Combobox.ts b/packages/combobox/src/Combobox.ts
index 2495b1537aa..729060d33e7 100644
--- a/packages/combobox/src/Combobox.ts
+++ b/packages/combobox/src/Combobox.ts
@@ -36,6 +36,7 @@ import '@spectrum-web-components/picker-button/sp-picker-button.js';
import '@spectrum-web-components/progress-circle/sp-progress-circle.js';
import '@spectrum-web-components/popover/sp-popover.js';
import { Textfield } from '@spectrum-web-components/textfield';
+import { FieldLabelMixin } from '@spectrum-web-components/field-label/src/FieldLabelMixin.js';
import type { Tooltip } from '@spectrum-web-components/tooltip';
import chevronStyles from '@spectrum-web-components/icon/src/spectrum-icon-chevron.css.js';
@@ -53,7 +54,7 @@ export type ComboboxOption = {
* @slot - Supply Menu Item elements to the default slot in order to populate the available options
* @slot tooltip - Tooltip to to be applied to the the Picker Button
*/
-export class Combobox extends Textfield {
+export class Combobox extends FieldLabelMixin(Textfield, 'field-label') {
public static override get styles(): CSSResultArray {
return [...super.styles, styles, chevronStyles];
}
@@ -348,44 +349,25 @@ export class Combobox extends Textfield {
super.onBlur(event);
}
- protected renderVisuallyHiddenLabels(): TemplateResult {
- /**
- * appliedLabel corresponds to `
`;
};
export const lightDOM = (): TemplateResult => {
return html`
-
- Fruit
-
+ Fruit
${fruits.map(
(fruit) => html`
@@ -167,13 +159,11 @@ export const lightDOM = (): TemplateResult => {
`
)}
-
- Countries
-
+ Countries
${countries.map(
(country) => html`
@@ -188,7 +178,6 @@ export const lightDOM = (): TemplateResult => {
export const withTooltip = (): TemplateResult => {
return html`
@@ -208,24 +197,21 @@ export const withTooltip = (): TemplateResult => {
export const withFieldLabel = (): TemplateResult => {
return html`
- Pick something
-
+
+ Pick something
+
`;
};
export const withLabelAttribute = (): TemplateResult => {
return html`
-
+
`;
};
export const withHelpText = (): TemplateResult => {
return html`
-
+
These are fruits found in the game "Animal Crossing: New Leaf".
@@ -250,15 +236,15 @@ class ControlledCombo extends LitElement {
override render(): TemplateResult {
return html`
-
- Retirement age (try entering a non-number)
-
+ >
+
+ Retirement age (try entering a non-number)
+
+
`;
}
diff --git a/packages/combobox/stories/index.ts b/packages/combobox/stories/index.ts
index 776b306ce3b..525a69eeab3 100644
--- a/packages/combobox/stories/index.ts
+++ b/packages/combobox/stories/index.ts
@@ -16,7 +16,6 @@ import {
} from '@spectrum-web-components/base';
import { Combobox, ComboboxOption } from '@spectrum-web-components/combobox';
import '@spectrum-web-components/combobox/sp-combobox.js';
-import '@spectrum-web-components/field-label/sp-field-label.js';
import { spreadProps } from '../../../test/lit-helpers';
export type StoryArgs = {
@@ -49,15 +48,15 @@ const handleInput =
export const ComboboxMarkup = (args: StoryArgs): TemplateResult => {
return html`
- Where do you live?
+ >
+ Where do you live?
+
`;
};
diff --git a/packages/combobox/test/combobox-a11y.test.ts b/packages/combobox/test/combobox-a11y.test.ts
index 8d76add3bbc..db9cb21db12 100644
--- a/packages/combobox/test/combobox-a11y.test.ts
+++ b/packages/combobox/test/combobox-a11y.test.ts
@@ -44,7 +44,7 @@ describe('Combobox accessibility', () => {
await elementUpdated(el);
await expect(el).to.be.accessible();
});
- it('renders accessibly with ', async () => {
+ it('renders accessibly with slotted label', async () => {
const test = await fixture(html`
${withFieldLabel()}
`);
@@ -64,7 +64,7 @@ describe('Combobox accessibility', () => {
await expect(el).to.be.accessible();
});
- it('manages its "name" value with ', async () => {
+ it('manages its "name" value with slotted label', async () => {
const test = await fixture(html`
${withFieldLabel()}
`);
diff --git a/packages/field-label/package.json b/packages/field-label/package.json
index 2a4d2769287..4f118e0c28b 100644
--- a/packages/field-label/package.json
+++ b/packages/field-label/package.json
@@ -29,12 +29,20 @@
"development": "./src/FieldLabel.dev.js",
"default": "./src/FieldLabel.js"
},
+ "./src/FieldLabelMixin.js": {
+ "development": "./src/FieldLabelMixin.dev.js",
+ "default": "./src/FieldLabelMixin.js"
+ },
"./src/field-label-overrides.css.js": "./src/field-label-overrides.css.js",
"./src/field-label.css.js": "./src/field-label.css.js",
"./src/index.js": {
"development": "./src/index.dev.js",
"default": "./src/index.js"
},
+ "./sp-field-label-mixin.js": {
+ "development": "./sp-field-label-mixin.dev.js",
+ "default": "./sp-field-label-mixin.js"
+ },
"./sp-field-label.js": {
"development": "./sp-field-label.dev.js",
"default": "./sp-field-label.js"
diff --git a/packages/field-label/src/FieldLabelMixin.ts b/packages/field-label/src/FieldLabelMixin.ts
new file mode 100644
index 00000000000..106075c6969
--- /dev/null
+++ b/packages/field-label/src/FieldLabelMixin.ts
@@ -0,0 +1,92 @@
+/**
+ * Copyright 2025 Adobe. All rights reserved.
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License. You may obtain a copy
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
+ * OF ANY KIND, either express or implied. See the License for the specific language
+ * governing permissions and limitations under the License.
+ */
+
+import {
+ CSSResultArray,
+ html,
+ nothing,
+ SpectrumElement,
+ TemplateResult,
+} from '@spectrum-web-components/base';
+import { property } from '@spectrum-web-components/base/src/decorators.js';
+import '@spectrum-web-components/icons-ui/icons/sp-icon-asterisk100.js';
+
+import styles from './field-label.css.js';
+import asteriskIconStyles from '@spectrum-web-components/icon/src/spectrum-icon-asterisk.css.js';
+import { ifDefined } from '@spectrum-web-components/base/src/directives.js';
+import { ObserveSlotText } from '@spectrum-web-components/shared';
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+type Constructor = new (...args: any[]) => T;
+
+export declare class FieldLabelMixinInterface {
+ disabled: boolean;
+ required: boolean;
+ sideAligned: 'start' | 'end';
+ slotHasContent: boolean;
+ manageTextObservedSlot(): void;
+ public renderFieldLabel(fieldId?: string): TemplateResult;
+}
+
+/**
+ * @mixin FieldLabelMixin
+ *
+ * @slot field-label - Text content of the label.
+ */
+export const FieldLabelMixin = >(
+ superClass: T,
+ slotName?: string,
+ excludedSelectors: string[] = []
+) => {
+ class FieldLabelMixinClass extends ObserveSlotText(
+ superClass,
+ slotName,
+ excludedSelectors
+ ) {
+ public static get styles(): CSSResultArray {
+ return [styles, asteriskIconStyles];
+ }
+
+ @property({ type: Boolean, reflect: true })
+ public disabled = false;
+
+ @property({ type: Boolean, reflect: true })
+ public required = false;
+
+ @property({ type: String, reflect: true, attribute: 'side-aligned' })
+ public sideAligned?: 'start' | 'end';
+
+ public renderFieldLabel(fieldId?: string): TemplateResult {
+ return html`
+
+
+ ${this.required
+ ? html`
+
+ `
+ : nothing}
+
+ `;
+ }
+ }
+ return FieldLabelMixinClass as Constructor & T;
+};
diff --git a/packages/number-field/README.md b/packages/number-field/README.md
index 87b56d1c206..84f23fa80fc 100644
--- a/packages/number-field/README.md
+++ b/packages/number-field/README.md
@@ -29,17 +29,15 @@ import { NumberField } from '@spectrum-web-components/number-field';
A number field consists of an input field for numeric values and optional stepper buttons for incrementing and decrementing the value. The stepper UI can be hidden using the `hide-stepper` attribute.
```html
-
- What is the air-speed velocity of an unladen swallow?
-
+>
+ What is the air-speed velocity of an unladen swallow?
+
```
### Options
@@ -94,16 +92,16 @@ An `` element will process its numeric value with `new Intl.Num
The following example uses the `signDisplay` option to include the plus sign for positive numbers, for example to display an offset from some value. In addition, it always displays a minimum of 1 digit after the decimal point, and allows up to 2 fraction digits. If the user enters more than 2 fraction digits, the result will be rounded.
```html
-Adjust exposure
+>
+ Adjust exposure
+
```
@@ -113,14 +111,14 @@ The following example uses the `signDisplay` option to include the plus sign for
The `style: 'percent'` option can be passed to the `formatOptions` property to treat the value as a percentage. In this mode, the value is multiplied by 100 before it is displayed, i.e. `0.45` is displayed as "45%". The reverse is also true: when the user enters a value, the `change` event will be triggered with the entered value divided by 100. When the percent option is enabled, the default step automatically changes to 0.01 such that incrementing and decrementing occurs by 1%. This can be overridden with the step property.
```html
-Sales tax
+>
+ Sales tax
+
```
@@ -132,9 +130,7 @@ The `style: 'currency'` option can be passed to the `formatOptions` property to
If you need to allow the user to change the currency, you should include a separate dropdown next to the `sp-number-field`. The `sp-number-field` itself will not determine the currency from the user input.
```html
-Transaction amount
+>
+ Transaction amount
+
```
@@ -156,16 +154,16 @@ If you need to allow the user to change the unit, you should include a separate
Note: The unit style is not currently supported in Safari. A [polyfill](https://formatjs.io/docs/polyfills/intl-numberformat/) may be necessary.
```html
-Package width
+>
+ Package width
+
```
@@ -175,15 +173,15 @@ Note: The unit style is not currently supported in Safari. A [polyfill](https://
While `Intl.NumberFormatOptions` does support a [wide range of units](https://tc39.es/proposal-unified-intl-numberformat/section6/locales-currencies-tz_proposed_out.html#sec-issanctionedsimpleunitidentifier), it is possible to encounter units (e.g. the graphics units of `pixel`, `pixels`, `points`, etc.) that are not supported therein. When this occurs, an `` element will attempt to polyfill support for this unit. See the following example delivering `{ style: "unit", unit: "px" }` below:
```html
-Document width in pixels
+>
+ Document width in pixels
+
```
Note: the polyfilling done here is very simplistic and is triggered by supplying options that would otherwise cause the `Intl.NumberFormat()` call to throw an error. Once the unsupporting unit of `px` causes the construction of the object to throw, a back up formatter/parser pair will be created without the supplied unit data. When the `style` is set to `unit`, the `unit` value of will be adopted as the _static_ unit display. This means that neither pluralization or translation will be handled within the `` element itself. If pluralization or translation is important to the delivered interface, please be sure to handle passing those strings into to element via the `formatOptions` property reactively to the value of the element or locale of that page in question.
@@ -197,8 +195,7 @@ The `min` and `max` properties can be used to limit the entered value to a speci
If a valid range is known ahead of time, it is a good idea to provide it to `` so it can optimize the experience. For example, when the minimum value is greater than or equal to zero, it is possible to use a numeric keyboard on iOS rather than a full text keyboard (necessary to enter a minus sign).
```html
-Red value
-
+Red value
```
@@ -211,32 +208,9 @@ If the user types a value that is between two steps and blurs the input, the val
```html
-Step
-
-
-Step + min
-
-
-Step + min + max
-
+Step
+Step + min
+Step + min + max
```
@@ -249,11 +223,7 @@ If the user types a value that is between two steps and blurs the input, the val
The `invalid` attribute indicates that the number field's value is invalid. When set, appropriate ARIA attributes will be automatically applied.
```html
-
- It's one banana, Michael, how much could it cost?
-
-
- Value should be between $0 and $0.3.
-
+>
+ It's one banana, Michael, how much could it cost?
+
+ Value should be between $0 and $0.3.
+
+
```
#### Valid
@@ -279,11 +251,7 @@ The `invalid` attribute indicates that the number field's value is invalid. When
The `valid` attribute indicates that the number field's value is valid.
```html
-
- It's one banana, Michael, how much could it cost?
-
+>
+ It's one banana, Michael, how much could it cost?
+
```
#### Required
@@ -306,10 +276,9 @@ The `valid` attribute indicates that the number field's value is valid.
Use the `required` attribute to indicate a number field value is required. Dictate the validity or invalidity state of the text entry with the `valid` or `invalid` attributes.
```html
-Count
-
-Size
-
+Count
+Count
+Size
```
#### Disabled
@@ -317,8 +286,7 @@ Use the `required` attribute to indicate a number field value is required. Dicta
The `disabled` attribute prevents the number field from receiving focus or events. The number field will appear faded.
```html
-Number of tickets
-
+Number of tickets
```
#### Read-only
@@ -326,8 +294,7 @@ The `disabled` attribute prevents the number field from receiving focus or event
Number fields have a `readonly` attribute for when they’re in the disabled state but still need their labels to be shown. This allows for content to be copied, but not interacted with or changed.
```html
-Number of tickets
-
+Number of tickets
```
### Behaviors
@@ -346,10 +313,9 @@ The input value incrementally increases or decreases by the value of the `step`
The `` component doesn't manage a default value by itself. This means that consumers can set the value of the number-field as an empty string by clearing the input. If we want the number-field to reset to a `default-value` when the user clears the input, we can listen for the `change` event on the number-field component and set its value to the desired `default-value` if the input is empty.
```html
-
+
Default value of this number field is 42
-
-
+