Skip to content
Open
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
Copy Markdown

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/Badge 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-web-components/Badge. - Dark Mode.normal.chromium.png 443 Changed
vr-tests-web-components/MenuList 2 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/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": "none",
"comment": "fix: display multiple selected dropdown options",
"packageName": "@fluentui/web-components",
"email": "brianbrady@microsoft.com",
"dependentChangeType": "none"
}
5 changes: 4 additions & 1 deletion packages/web-components/src/dropdown/dropdown.base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,10 @@ export class BaseDropdown extends FASTElement {
style: 'narrow',
});

const displayValue = this.listFormatter.format(this.selectedOptions.map(x => x.text));
const selectedOptions = this.selectedOptions;
const displayValue = this.multiple
? selectedOptions.map(x => x.text).join(', ')
Copy link
Copy Markdown
Contributor

@marchbox marchbox May 8, 2026

Choose a reason for hiding this comment

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

I think we do want to use the list formatter for multiple, joining the text with a comma and a whitespace will not work internationally.

: this.listFormatter.format(selectedOptions.map(x => x.text));
toggleState(this.elementInternals, 'placeholder-shown', !displayValue);

if (this.isCombobox) {
Expand Down
37 changes: 37 additions & 0 deletions packages/web-components/src/dropdown/dropdown.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,43 @@ test.describe('Dropdown', () => {
await expect(button).toHaveCount(1);
});

test('should display comma-separated selected options when multiple options are initially selected', async ({
fastPage,
}) => {
const { element } = fastPage;
const button = element.locator('button');

await fastPage.setTemplate(/* html */ `
<fluent-dropdown multiple>
<fluent-listbox>
<fluent-option>Option 1</fluent-option>
<fluent-option selected>Option 2 (Selectable)</fluent-option>
<fluent-option selected>Option 3 (Selectable)</fluent-option>
</fluent-listbox>
</fluent-dropdown>
`);

await expect(button).toHaveText('Option 2 (Selectable), Option 3 (Selectable)');
});

test('should update the comma-separated selected options display when selecting multiple options', async ({
fastPage,
}) => {
const { element } = fastPage;
const button = element.locator('button');

await fastPage.setTemplate({ attributes: { multiple: true } });

await element.click();
await element.locator('fluent-option[value=banana]').click();

await expect(button).toHaveText('Banana');

await element.locator('fluent-option[value=orange]').click();

await expect(button).toHaveText('Banana, Orange');
});

test('should render an input when the type attribute is set to "combobox"', async ({ fastPage }) => {
const { element } = fastPage;
const input = element.locator('input');
Expand Down
15 changes: 13 additions & 2 deletions packages/web-components/src/dropdown/dropdown.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,20 @@ export const Default: Story = {

export const MultipleSelection: Story = {
args: {
...Default.args,
multiple: true,
placeholder: 'Select fruits',
placeholder: 'Best pet',
slot: 'input',
slottedContent: () => [
{ selected: true, value: 'cat', slottedContent: () => 'Cat' },
{ selected: true, value: 'dog', slottedContent: () => 'Dog' },
{ selected: true, value: 'fish', slottedContent: () => 'Fish' },
{ selected: true, value: 'hamster', slottedContent: () => 'Hamster' },
{ selected: true, value: 'snake', slottedContent: () => 'Snake' },
{ selected: true, value: 'bird', slottedContent: () => 'Bird' },
{ selected: true, value: 'wolf', slottedContent: () => 'Wolf' },
{ selected: true, value: 'beetle', slottedContent: () => 'Beetle' },
{ selected: true, value: 'squirrel', slottedContent: () => 'Squirrel' },
],
},
};

Expand Down
6 changes: 6 additions & 0 deletions packages/web-components/src/dropdown/dropdown.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ export const styles = css`
cursor: pointer;
}

:host([multiple]) ::slotted(button) {
min-width: 0;
white-space: normal;
}

::slotted(input) {
cursor: text;
}
Expand All @@ -122,6 +127,7 @@ export const styles = css`
aspect-ratio: 1;
color: ${colorNeutralForeground3};
display: inline-flex;
flex-shrink: 0;
justify-content: center;
width: 20px;
}
Expand Down
16 changes: 16 additions & 0 deletions packages/web-components/src/listbox/listbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,23 @@ export class Listbox extends FASTElement {
next?.forEach((option, index) => {
option.elementInternals.ariaPosInSet = `${index + 1}`;
option.elementInternals.ariaSetSize = `${next.length}`;

if (this.dropdown) {
option.multiple = !!this.multiple;
option.disabled = option.disabledAttribute || this.dropdown.disabled;
option.name = this.dropdown.name;
}
});

if (this.dropdown) {
next
?.filter(option => option.defaultSelected)
.forEach((option, index) => {
option.selected = !!this.multiple || index === 0;
});

this.dropdown.setValidity();
}
Comment on lines +87 to +102
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this related? It seems like the primary change here needs to be styles.

The dropdown when constrained to space wraps to another line (the intent of this PR). It seems like this could be a max-width issue either in the component or example. I'm not sure what the logic changes are here.

Image

}

/**
Expand Down
Loading