Skip to content
Draft
Show file tree
Hide file tree
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
Copy link

@github-actions github-actions bot Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🕵🏾‍♀️ visual changes to review in the Visual Change Report

vr-tests-web-components/Accordion 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-web-components/Accordion. - Dark Mode.normal.chromium_1.png 3154 Changed
vr-tests-web-components/MenuList 3 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-web-components/MenuList. - Dark Mode.normal.chromium.png 498 Changed
vr-tests-web-components/MenuList. - RTL.2nd selected.chromium.png 17 Changed
vr-tests-web-components/MenuList. - RTL.2nd selected.chromium_3.png 38816 Changed
vr-tests-web-components/RadioGroup 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-web-components/RadioGroup. - Dark Mode.1st selected.chromium_2.png 119 Changed

"type": "prerelease",
"comment": "fix: update option selected condition to check for elementInternals before setting form value and ariaSelected",
"packageName": "@fluentui/web-components",
"email": "863023+radium-v@users.noreply.github.com",
"dependentChangeType": "patch"
}
10 changes: 7 additions & 3 deletions packages/web-components/docs/web-components.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -3040,6 +3040,12 @@ export class Listbox extends FASTElement {
// @internal
beforetoggleHandler(e: ToggleEvent): boolean | undefined;
clickHandler(e: PointerEvent): boolean | void;
// (undocumented)
connectedCallback(): void;
// @internal
defaultSlot: HTMLSlotElement;
// @internal
protected defaultSlotChanged(): void;
// @internal
dropdown?: BaseDropdown;
// @internal
Expand All @@ -3048,8 +3054,6 @@ export class Listbox extends FASTElement {
get enabledOptions(): DropdownOption[];
// @internal
handleChange(source: any, propertyName?: string): void;
// @override
id: string;
multiple?: boolean;
multipleChanged(prev: boolean | undefined, next: boolean | undefined): void;
options: DropdownOption[];
Expand All @@ -3059,7 +3063,7 @@ export class Listbox extends FASTElement {
selectedIndex: number;
get selectedOptions(): DropdownOption[];
selectOption(index?: number): void;
slotchangeHandler(e: Event): void;
slotchangeHandler(e?: Event): void;
}

// @public
Expand Down
5 changes: 2 additions & 3 deletions packages/web-components/src/listbox/listbox.template.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type ElementViewTemplate, html } from '@microsoft/fast-element';
import { type ElementViewTemplate, html, ref } from '@microsoft/fast-element';
import type { Listbox } from './listbox.js';

/**
Expand All @@ -11,11 +11,10 @@ import type { Listbox } from './listbox.js';
export function listboxTemplate<T extends Listbox>(): ElementViewTemplate<T> {
return html<T>`
<template
id="${x => x.id}"
@beforetoggle="${(x, c) => x.beforetoggleHandler(c.event as ToggleEvent)}"
@click="${(x, c) => x.clickHandler(c.event as PointerEvent)}"
>
<slot @slotchange="${(x, c) => x.slotchangeHandler(c.event)}"></slot>
<slot ${ref('defaultSlot')} @slotchange="${(x, c) => x.slotchangeHandler(c.event)}"></slot>
</template>
`;
}
Expand Down
41 changes: 31 additions & 10 deletions packages/web-components/src/listbox/listbox.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { attr, FASTElement, observable, Updates } from '@microsoft/fast-element';
import { FASTElement, observable, Updates } from '@microsoft/fast-element';
import type { BaseDropdown } from '../dropdown/dropdown.base.js';
import type { DropdownOption } from '../option/option.js';
import { isDropdownOption } from '../option/option.options.js';
Expand All @@ -22,15 +22,28 @@ import { uniqueId } from '../utils/unique-id.js';
*/
export class Listbox extends FASTElement {
/**
* Sets the listbox ID to a unique value if one is not provided.
* A reference to the default slot element.
*
* @override
* @public
* @internal
*/
@observable
public defaultSlot!: HTMLSlotElement;

/**
* Calls the `slotchangeHandler` when the `defaultSlot` element is assigned
* via the `ref` directive in the template.
*
* @internal
* @remarks
* HTML Attribute: `id`
* This is needed for scenarios where the slot element is already present
* when the component is connected, such as when the instance is hydrating in
* a declarative Shadow DOM environment. In this case, the `slotchange` event
* doesn't fire during initialization, so the `slotchangeHandler` needs to be
* called manually to populate the options.
*/
@attr({ attribute: 'id', mode: 'fromView' })
public override id: string = uniqueId('listbox-');
protected defaultSlotChanged() {
this.slotchangeHandler();
}

/**
* Indicates whether the listbox allows multiple selection.
Expand Down Expand Up @@ -165,6 +178,15 @@ export class Listbox extends FASTElement {
this.elementInternals.role = 'listbox';
}

connectedCallback(): void {
super.connectedCallback();

// The listbox needs to have an id for the dropdown to reference via
// `aria-controls`. If an id is not present on connection, a unique one is
// generated and assigned to the element.
this.id = this.id || uniqueId('listbox-');
}

/**
* Handles observable subscriptions for the listbox.
*
Expand Down Expand Up @@ -215,10 +237,9 @@ export class Listbox extends FASTElement {
* @param e - The slotchange event
* @public
*/
public slotchangeHandler(e: Event): void {
const target = e.target as HTMLSlotElement;
public slotchangeHandler(e?: Event): void {
waitForConnectedDescendants(this, () => {
const options = target
const options = this.defaultSlot
.assignedElements()
.filter<DropdownOption>((option): option is DropdownOption => isDropdownOption(option));

Expand Down
2 changes: 1 addition & 1 deletion packages/web-components/src/option/option.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ export class DropdownOption extends FASTElement implements Start {
this.currentSelected = next;

Updates.enqueue(() => {
if (this.$fastController.isConnected) {
if (this.elementInternals) {
this.setFormValue(next ? this.value : null);

this.elementInternals.ariaSelected = next ? 'true' : 'false';
Expand Down
Loading