Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AutoComplete] Allow focusable Badge dismiss buttons (accessibility) #2272

Merged
merged 3 commits into from
Jun 26, 2024
Merged
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
Expand Up @@ -4330,6 +4330,12 @@
Allows for capturing a mouse click on an icon.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentIcon`1.Focusable">
<summary>
Gets or sets whether the icon is focusable (adding tabindex="0" and role="button"),
allows the icon to be focused sequentially (generally with the Tab key).
</summary>
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.FluentIcon`1.OnClickHandlerAsync(Microsoft.AspNetCore.Components.Web.MouseEventArgs)">
<summary />
</member>
Expand Down
2 changes: 1 addition & 1 deletion src/Core/Components/Badge/FluentBadge.razor
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
@ChildContent
@if (OnDismissClick.HasDelegate)
{
<FluentIcon Value="@(DismissIcon ?? new CoreIcons.Regular.Size24.Dismiss())" Width="12px" Style="margin: 2px 0px 0px 2px;" Title="@DismissTitle" OnClick="OnDismissClickHandlerAsync" />
<FluentIcon Value="@(DismissIcon ?? new CoreIcons.Regular.Size24.Dismiss())" Width="12px" Style="margin: 2px 0px 0px 2px;" Title="@DismissTitle" OnClick="OnDismissClickHandlerAsync" Focusable="true" />
}
</span>

Expand Down
4 changes: 2 additions & 2 deletions src/Core/Components/Icons/FluentIcon.razor
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

@if (_icon.Size != IconSize.Custom && _icon.ContainsSVG)
{
<svg id="@Id" slot="@Slot" class="@ClassValue" style="@StyleValue" focusable="false" viewBox="@($"0 0 {((int)_icon.Size)} {((int)_icon.Size)}")"
<svg id="@Id" slot="@Slot" class="@ClassValue" style="@StyleValue" focusable="@(Focusable ? "true" : "false")" tabindex="@(Focusable ? 0 : null)" role="@(Focusable ? "button" : null)" viewBox="@($"0 0 {((int)_icon.Size)} {((int)_icon.Size)}")"
aria-hidden="true" @onkeydown="@OnKeyDownAsync" @onclick="@OnClickHandlerAsync" @attributes="@AdditionalAttributes">
@if (!string.IsNullOrEmpty(Title))
{
Expand All @@ -15,6 +15,6 @@
}
else
{
<div id="@Id" slot="@Slot" class="@ClassValue" style="@StyleValue" title="@Title"
<div id="@Id" slot="@Slot" class="@ClassValue" style="@StyleValue" title="@Title" tabindex="@(Focusable ? 0 : null)" role="@(Focusable ? "button" : null)"
@attributes="@AdditionalAttributes" @onkeydown="@OnKeyDownAsync" @onclick="@OnClickHandlerAsync">@((MarkupString)@_icon.Content)</div>
}
7 changes: 7 additions & 0 deletions src/Core/Components/Icons/FluentIcon.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ public Icon Value
[Parameter]
public EventCallback<MouseEventArgs> OnClick { get; set; }

/// <summary>
/// Gets or sets whether the icon is focusable (adding tabindex="0" and role="button"),
/// allows the icon to be focused sequentially (generally with the Tab key).
/// </summary>
[Parameter]
public bool Focusable { get; set; } = false;

/// <summary />
protected virtual Task OnClickHandlerAsync(MouseEventArgs e)
{
Expand Down
5 changes: 4 additions & 1 deletion src/Core/Components/List/FluentAutocomplete.razor
Original file line number Diff line number Diff line change
Expand Up @@ -203,10 +203,13 @@
{
if (SelectedOptionTemplate == null)
{
var text = @GetOptionText(item);

<FluentBadge Appearance="@AspNetCore.Components.Appearance.Neutral"
OnDismissClick="@(e => RemoveSelectedItemAsync(item))"
DismissTitle="@(string.Format(AccessibilityRemoveItem, text))"
aria-label="@GetOptionText(item)">
@GetOptionText(item)
@text
</FluentBadge>
}
else
Expand Down
6 changes: 6 additions & 0 deletions src/Core/Components/List/FluentAutocomplete.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public partial class FluentAutocomplete<TOption> : ListComponentBase<TOption> wh
public static string AccessibilitySelected = "Selected {0}";
public static string AccessibilityNotFound = "No items found";
public static string AccessibilityReachedMaxItems = "The maximum number of selected items has been reached.";
public static string AccessibilityRemoveItem = "Remove {0}";
internal const string JAVASCRIPT_FILE = "./_content/Microsoft.FluentUI.AspNetCore.Components/Components/List/FluentAutocomplete.razor.js";

public new FluentTextField? Element { get; set; } = default!;
Expand Down Expand Up @@ -529,6 +530,11 @@ public async Task RemoveSelectedItemAsync(TOption? item)

RemoveSelectedItem(item);
await RaiseChangedEventsAsync();

if (Module != null)
{
await Module.InvokeVoidAsync("focusOn", Id);
}
}

/// <summary />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@

<div class=" fluent-autocomplete-multiselect" style="width: 100%;" b-hg72r5b4ox="">
<fluent-text-field style="width: 100%; min-width: 100%;" placeholder="" id="xxx" value="" current-value="" appearance="outline" blazor:onchange="1" role="combobox" aria-expanded="true" aria-controls="myComponent-popup" aria-label="2-Vincent Baaij (2 of 3)" blazor:onclick="2" blazor:oninput="3" blazor:onfocusout="4" blazor:elementreference="">
<fluent-text-field style="width: 100%; min-width: 100%;" placeholder="" id="xxx" value="" current-value="" appearance="outline" blazor:onchange="1" role="combobox" aria-expanded="true" aria-controls="myComponent-popup" aria-label="2-Vincent Baaij (2 of 3)" blazor:onclick="2" blazor:oninput="3" blazor:elementreference="">
<fluent-horizontal-scroll id="xxx" style="width: 100%;" slot="start" b-hg72r5b4ox="">
<fluent-flipper onclick="event.stopPropagation(); document.getElementById('myComponent-scroll').scrollToPrevious();" slot="previous-flipper" aria-hidden="false" aria-label="Previous" title="Previous" role="button" tabindex="0" class="previous fluent-autocomplete-previous" direction="previous" b-hg72r5b4ox=""></fluent-flipper>
<fluent-flipper onclick="event.stopPropagation(); document.getElementById('myComponent-scroll').scrollToNext();" slot="next-flipper" aria-hidden="false" aria-label="Next" title="Next" role="button" tabindex="0" class="next fluent-autocomplete-next" direction="next" b-hg72r5b4ox=""></fluent-flipper>
<fluent-badge id="xxx" appearance="neutral" blazor:onclick="5" aria-label="1-Denis Voituron" blazor:elementreference="">
<span style="width: 100%; display: flex; align-items: center; justify-content: center; white-space: nowrap;">1-Denis Voituron<svg style="width: 12px; fill: var(--accent-fill-rest); cursor: pointer; margin: 2px 0px 0px 2px;" focusable="false" viewBox="0 0 24 24" aria-hidden="true" blazor:onkeydown="9" blazor:onclick="10">
<fluent-badge id="xxx" appearance="neutral" blazor:onclick="4" aria-label="1-Denis Voituron" blazor:elementreference="">
<span style="width: 100%; display: flex; align-items: center; justify-content: center; white-space: nowrap;">
1-Denis Voituron
<svg style="width: 12px; fill: var(--accent-fill-rest); cursor: pointer; margin: 2px 0px 0px 2px;" focusable="true" tabindex="0" role="button" viewBox="0 0 24 24" aria-hidden="true" blazor:onkeydown="9" blazor:onclick="10">
<title>Remove 1-Denis Voituron</title>
<path d="m4.4 4.55.07-.08a.75.75 0 0 1 .98-.07l.08.07L12 10.94l6.47-6.47a.75.75 0 1 1 1.06 1.06L13.06 12l6.47 6.47c.27.27.3.68.07.98l-.07.08a.75.75 0 0 1-.98.07l-.08-.07L12 13.06l-6.47 6.47a.75.75 0 0 1-1.06-1.06L10.94 12 4.47 5.53a.75.75 0 0 1-.07-.98l.07-.08-.07.08Z"></path>
</svg>
</span>
</fluent-badge>
<fluent-badge id="xxx" appearance="neutral" blazor:onclick="6" aria-label="2-Vincent Baaij" blazor:elementreference="">
<span style="width: 100%; display: flex; align-items: center; justify-content: center; white-space: nowrap;">2-Vincent Baaij<svg style="width: 12px; fill: var(--accent-fill-rest); cursor: pointer; margin: 2px 0px 0px 2px;" focusable="false" viewBox="0 0 24 24" aria-hidden="true" blazor:onkeydown="11" blazor:onclick="12">
<fluent-badge id="xxx" appearance="neutral" blazor:onclick="5" aria-label="2-Vincent Baaij" blazor:elementreference="">
<span style="width: 100%; display: flex; align-items: center; justify-content: center; white-space: nowrap;">
2-Vincent Baaij
<svg style="width: 12px; fill: var(--accent-fill-rest); cursor: pointer; margin: 2px 0px 0px 2px;" focusable="true" tabindex="0" role="button" viewBox="0 0 24 24" aria-hidden="true" blazor:onkeydown="11" blazor:onclick="12">
<title>Remove 2-Vincent Baaij</title>
<path d="m4.4 4.55.07-.08a.75.75 0 0 1 .98-.07l.08.07L12 10.94l6.47-6.47a.75.75 0 1 1 1.06 1.06L13.06 12l6.47 6.47c.27.27.3.68.07.98l-.07.08a.75.75 0 0 1-.98.07l-.08-.07L12 13.06l-6.47 6.47a.75.75 0 0 1-1.06-1.06L10.94 12 4.47 5.53a.75.75 0 0 1-.07-.98l.07-.08-.07.08Z"></path>
</svg>
</span>
</fluent-badge>
</fluent-horizontal-scroll>
<svg slot="end" style="width: 12px; fill: var(--accent-fill-rest); cursor: pointer;" focusable="false" viewBox="0 0 16 16" aria-hidden="true" blazor:onkeydown="7" blazor:onclick="8" tabindex="0" role="button">
<svg slot="end" style="width: 12px; fill: var(--accent-fill-rest); cursor: pointer;" focusable="false" viewBox="0 0 16 16" aria-hidden="true" blazor:onkeydown="6" blazor:onclick="7" blazor:onfocus="8" tabindex="0" role="button">
<title>Clear</title>
<path d="m2.59 2.72.06-.07a.5.5 0 0 1 .63-.06l.07.06L8 7.29l4.65-4.64a.5.5 0 0 1 .7.7L8.71 8l4.64 4.65c.18.17.2.44.06.63l-.06.07a.5.5 0 0 1-.63.06l-.07-.06L8 8.71l-4.65 4.64a.5.5 0 0 1-.7-.7L7.29 8 2.65 3.35a.5.5 0 0 1-.06-.63l.06-.07-.06.07Z"></path>
</svg>
Expand All @@ -34,4 +40,4 @@
</div>
</div>
</fluent-anchored-region>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@

<div class=" fluent-autocomplete-multiselect" style="width: 100%;" b-hg72r5b4ox="">
<fluent-text-field style="width: 100%; min-width: 100%;" placeholder="" id="xxx" value="" current-value="" appearance="outline" blazor:onchange="1" role="combobox" aria-expanded="true" aria-controls="myComponent-popup" aria-label="1-Denis Voituron (1 of 3)" blazor:onclick="2" blazor:oninput="3" blazor:onfocusout="4" blazor:elementreference="">
<fluent-text-field style="width: 100%; min-width: 100%;" placeholder="" id="xxx" value="" current-value="" appearance="outline" blazor:onchange="1" role="combobox" aria-expanded="true" aria-controls="myComponent-popup" aria-label="1-Denis Voituron (1 of 3)" blazor:onclick="2" blazor:oninput="3" blazor:elementreference="">
<fluent-horizontal-scroll id="xxx" style="width: 100%;" slot="start" b-hg72r5b4ox="">
<fluent-flipper onclick="event.stopPropagation(); document.getElementById('myComponent-scroll').scrollToPrevious();" slot="previous-flipper" aria-hidden="false" aria-label="Previous" title="Previous" role="button" tabindex="0" class="previous fluent-autocomplete-previous" direction="previous" b-hg72r5b4ox=""></fluent-flipper>
<fluent-flipper onclick="event.stopPropagation(); document.getElementById('myComponent-scroll').scrollToNext();" slot="next-flipper" aria-hidden="false" aria-label="Next" title="Next" role="button" tabindex="0" class="next fluent-autocomplete-next" direction="next" b-hg72r5b4ox=""></fluent-flipper>
<fluent-badge id="xxx" appearance="neutral" blazor:onclick="5" aria-label="1-Denis Voituron" blazor:elementreference="">
<span style="width: 100%; display: flex; align-items: center; justify-content: center; white-space: nowrap;">1-Denis Voituron<svg style="width: 12px; fill: var(--accent-fill-rest); cursor: pointer; margin: 2px 0px 0px 2px;" focusable="false" viewBox="0 0 24 24" aria-hidden="true" blazor:onkeydown="9" blazor:onclick="10">
<fluent-badge id="xxx" appearance="neutral" blazor:onclick="4" aria-label="1-Denis Voituron" blazor:elementreference="">
<span style="width: 100%; display: flex; align-items: center; justify-content: center; white-space: nowrap;">1-Denis Voituron<svg style="width: 12px; fill: var(--accent-fill-rest); cursor: pointer; margin: 2px 0px 0px 2px;" focusable="true" tabindex="0" role="button" viewBox="0 0 24 24" aria-hidden="true" blazor:onkeydown="9" blazor:onclick="10">
<title>Remove 1-Denis Voituron</title>
<path d="m4.4 4.55.07-.08a.75.75 0 0 1 .98-.07l.08.07L12 10.94l6.47-6.47a.75.75 0 1 1 1.06 1.06L13.06 12l6.47 6.47c.27.27.3.68.07.98l-.07.08a.75.75 0 0 1-.98.07l-.08-.07L12 13.06l-6.47 6.47a.75.75 0 0 1-1.06-1.06L10.94 12 4.47 5.53a.75.75 0 0 1-.07-.98l.07-.08-.07.08Z"></path>
</svg>
</span>
</fluent-badge>
<fluent-badge id="xxx" appearance="neutral" blazor:onclick="6" aria-label="2-Vincent Baaij" blazor:elementreference="">
<span style="width: 100%; display: flex; align-items: center; justify-content: center; white-space: nowrap;">2-Vincent Baaij<svg style="width: 12px; fill: var(--accent-fill-rest); cursor: pointer; margin: 2px 0px 0px 2px;" focusable="false" viewBox="0 0 24 24" aria-hidden="true" blazor:onkeydown="11" blazor:onclick="12">
<fluent-badge id="xxx" appearance="neutral" blazor:onclick="5" aria-label="2-Vincent Baaij" blazor:elementreference="">
<span style="width: 100%; display: flex; align-items: center; justify-content: center; white-space: nowrap;">2-Vincent Baaij<svg style="width: 12px; fill: var(--accent-fill-rest); cursor: pointer; margin: 2px 0px 0px 2px;" focusable="true" tabindex="0" role="button" viewBox="0 0 24 24" aria-hidden="true" blazor:onkeydown="11" blazor:onclick="12">
<title>Remove 2-Vincent Baaij</title>
<path d="m4.4 4.55.07-.08a.75.75 0 0 1 .98-.07l.08.07L12 10.94l6.47-6.47a.75.75 0 1 1 1.06 1.06L13.06 12l6.47 6.47c.27.27.3.68.07.98l-.07.08a.75.75 0 0 1-.98.07l-.08-.07L12 13.06l-6.47 6.47a.75.75 0 0 1-1.06-1.06L10.94 12 4.47 5.53a.75.75 0 0 1-.07-.98l.07-.08-.07.08Z"></path>
</svg>
</span>
</fluent-badge>
</fluent-horizontal-scroll>
<svg slot="end" style="width: 12px; fill: var(--accent-fill-rest); cursor: pointer;" focusable="false" viewBox="0 0 16 16" aria-hidden="true" blazor:onkeydown="7" blazor:onclick="8" tabindex="0" role="button">
<svg slot="end" style="width: 12px; fill: var(--accent-fill-rest); cursor: pointer;" focusable="false" viewBox="0 0 16 16" aria-hidden="true" blazor:onkeydown="6" blazor:onclick="7" blazor:onfocus="8" tabindex="0" role="button">
<title>Clear</title>
<path d="m2.59 2.72.06-.07a.5.5 0 0 1 .63-.06l.07.06L8 7.29l4.65-4.64a.5.5 0 0 1 .7.7L8.71 8l4.64 4.65c.18.17.2.44.06.63l-.06.07a.5.5 0 0 1-.63.06l-.07-.06L8 8.71l-4.65 4.64a.5.5 0 0 1-.7-.7L7.29 8 2.65 3.35a.5.5 0 0 1-.06-.63l.06-.07-.06.07Z"></path>
</svg>
Expand All @@ -34,4 +36,4 @@
</div>
</div>
</fluent-anchored-region>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@

<div class=" fluent-autocomplete-multiselect" style="width: 100%;" b-hg72r5b4ox="">
<fluent-text-field style="width: 100%; min-width: 100%;" placeholder="" id="xxx" value="" current-value="" appearance="outline" blazor:onchange="1" role="combobox" aria-expanded="true" aria-controls="myComponent-popup" aria-label="1-Denis Voituron (1 of 3)" blazor:onclick="2" blazor:oninput="3" blazor:onfocusout="4" blazor:elementreference="">
<fluent-text-field style="width: 100%; min-width: 100%;" placeholder="" id="xxx" value="" current-value="" appearance="outline" blazor:onchange="1" role="combobox" aria-expanded="true" aria-controls="myComponent-popup" aria-label="1-Denis Voituron (1 of 3)" blazor:onclick="2" blazor:oninput="3" blazor:elementreference="">
<fluent-horizontal-scroll id="xxx" style="width: 100%;" slot="start" b-hg72r5b4ox="">
<fluent-flipper onclick="event.stopPropagation(); document.getElementById('myComponent-scroll').scrollToPrevious();" slot="previous-flipper" aria-hidden="false" aria-label="Previous" title="Previous" role="button" tabindex="0" class="previous fluent-autocomplete-previous" direction="previous" b-hg72r5b4ox=""></fluent-flipper>
<fluent-flipper onclick="event.stopPropagation(); document.getElementById('myComponent-scroll').scrollToNext();" slot="next-flipper" aria-hidden="false" aria-label="Next" title="Next" role="button" tabindex="0" class="next fluent-autocomplete-next" direction="next" b-hg72r5b4ox=""></fluent-flipper>
<fluent-badge id="xxx" appearance="neutral" blazor:onclick="5" aria-label="1-Denis Voituron" blazor:elementreference="">
<span style="width: 100%; display: flex; align-items: center; justify-content: center; white-space: nowrap;">1-Denis Voituron<svg style="width: 12px; fill: var(--accent-fill-rest); cursor: pointer; margin: 2px 0px 0px 2px;" focusable="false" viewBox="0 0 24 24" aria-hidden="true" blazor:onkeydown="9" blazor:onclick="10">
<fluent-badge id="xxx" appearance="neutral" blazor:onclick="4" aria-label="1-Denis Voituron" blazor:elementreference="">
<span style="width: 100%; display: flex; align-items: center; justify-content: center; white-space: nowrap;">1-Denis Voituron<svg style="width: 12px; fill: var(--accent-fill-rest); cursor: pointer; margin: 2px 0px 0px 2px;" focusable="true" tabindex="0" role="button" viewBox="0 0 24 24" aria-hidden="true" blazor:onkeydown="9" blazor:onclick="10">
<title>Remove 1-Denis Voituron</title>
<path d="m4.4 4.55.07-.08a.75.75 0 0 1 .98-.07l.08.07L12 10.94l6.47-6.47a.75.75 0 1 1 1.06 1.06L13.06 12l6.47 6.47c.27.27.3.68.07.98l-.07.08a.75.75 0 0 1-.98.07l-.08-.07L12 13.06l-6.47 6.47a.75.75 0 0 1-1.06-1.06L10.94 12 4.47 5.53a.75.75 0 0 1-.07-.98l.07-.08-.07.08Z"></path>
</svg>
</span>
</fluent-badge>
<fluent-badge id="xxx" appearance="neutral" blazor:onclick="6" aria-label="2-Vincent Baaij" blazor:elementreference="">
<span style="width: 100%; display: flex; align-items: center; justify-content: center; white-space: nowrap;">2-Vincent Baaij<svg style="width: 12px; fill: var(--accent-fill-rest); cursor: pointer; margin: 2px 0px 0px 2px;" focusable="false" viewBox="0 0 24 24" aria-hidden="true" blazor:onkeydown="11" blazor:onclick="12">
<fluent-badge id="xxx" appearance="neutral" blazor:onclick="5" aria-label="2-Vincent Baaij" blazor:elementreference="">
<span style="width: 100%; display: flex; align-items: center; justify-content: center; white-space: nowrap;">2-Vincent Baaij<svg style="width: 12px; fill: var(--accent-fill-rest); cursor: pointer; margin: 2px 0px 0px 2px;" focusable="true" tabindex="0" role="button" viewBox="0 0 24 24" aria-hidden="true" blazor:onkeydown="11" blazor:onclick="12">
<title>Remove 2-Vincent Baaij</title>
<path d="m4.4 4.55.07-.08a.75.75 0 0 1 .98-.07l.08.07L12 10.94l6.47-6.47a.75.75 0 1 1 1.06 1.06L13.06 12l6.47 6.47c.27.27.3.68.07.98l-.07.08a.75.75 0 0 1-.98.07l-.08-.07L12 13.06l-6.47 6.47a.75.75 0 0 1-1.06-1.06L10.94 12 4.47 5.53a.75.75 0 0 1-.07-.98l.07-.08-.07.08Z"></path>
</svg>
</span>
</fluent-badge>
</fluent-horizontal-scroll>
<svg slot="end" style="width: 12px; fill: var(--accent-fill-rest); cursor: pointer;" focusable="false" viewBox="0 0 16 16" aria-hidden="true" blazor:onkeydown="7" blazor:onclick="8" tabindex="0" role="button">
<svg slot="end" style="width: 12px; fill: var(--accent-fill-rest); cursor: pointer;" focusable="false" viewBox="0 0 16 16" aria-hidden="true" blazor:onkeydown="6" blazor:onclick="7" blazor:onfocus="8" tabindex="0" role="button">
<title>Clear</title>
<path d="m2.59 2.72.06-.07a.5.5 0 0 1 .63-.06l.07.06L8 7.29l4.65-4.64a.5.5 0 0 1 .7.7L8.71 8l4.64 4.65c.18.17.2.44.06.63l-.06.07a.5.5 0 0 1-.63.06l-.07-.06L8 8.71l-4.65 4.64a.5.5 0 0 1-.7-.7L7.29 8 2.65 3.35a.5.5 0 0 1-.06-.63l.06-.07-.06.07Z"></path>
</svg>
Expand All @@ -34,4 +36,4 @@
</div>
</div>
</fluent-anchored-region>
</div>
</div>
Loading
Loading