Ant Design Select dropdown list aria label accessibility - antd

I am trying to implement accessibility for my dropdown list. I used antd's Select component. But my problem is that when I use keyboard up and down arrow keys to navigate in the listbox(dropdown list), the computer does not read aria label that I passed in to the out, actually I can't even pass aria label and tabIndex into Option. Do you have any idea how I can fix this problem?
<Select
showSearch
style={{ width: 200 }}
placeholder="Select a person"
optionFilterProp="children"
onChange={onChange}
onFocus={onFocus}
onBlur={onBlur}
onSearch={onSearch}
filterOption={(input, option) =>
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
>
<div aria-label={"jack"} tabIndex={0}><Option aria-label={"jack"} tabIndex={0} value="jack">Jack</Option>
<Select.Option aria-label={"lucy"} tabIndex={0} value="lucy">
Lucy
</Select.Option>
<Select.Option aria-label={"tom"} tabIndex={0} value="tom">
Tom
</Select.Option>
</Select>
Thanks

I may be misunderstanding, but it seems to me that your solution works. I reproduced your component at the following CodeSandbox link.
You can inspect the dropdown list and the aria-labels are indeed present (see dev tools pic below) and on my Mac VoiceOver does speak the names of each of the menu items.

Related

Removing selected option in multiple select2 clears all options

Using Laravel livewire, bootstrap 5 modal and select 2.
Select2 (s2) without multiple works fine. It's populated, selections save to the component, clearing is also fine.
When an s2 has multiple attribute, removing a selected option clears all the options and nothing is displayed in the results drop down. When adding a selection, this doesn't happen.
If I do a dispatchBrowserEvent and re-init the s2 it does work again.
My question is why does removing an s2 option require a re-init but an add doesn't.
Seems to be something to do with the rendering in render().
Some code...
Blade:
<div wire:ignore>
<select id="selectedTrades" wire:model.defer="selectedTrades" class="select-2" multiple="multiple" data-field="selectedTrades" data-allow-clear="false">
#foreach ($contractor_trades as $trade)
<option value="{{ $trade['id'] }}">{{ $trade['name'] }}</option>
#endforeach
</div>
Standard stuff. wire.ignore around the s2. The modal has wire:ignore.self.
JS:
$('.select-2').on('change', function (e)
{
var $this = $(this);
livewire.emit('setSelect2Property', $this.attr('data-field'), $this.val());
});
Component:
public function setSelect2Property($property, $value)
{
$this->$property = $value;
}
Just sets $this->selectedTrades to the array sent.
Adding:
The drop down has the options as expected.
Removing:
The thin light line under it is the container for the results that's now empty. The original select element does still have its options.
If I remove the livewire.emit from the js to test, the s2 behaves correctly.
I think it has to do with the components render method. I can't figure out what is happening different when I add versus remove.
I got this to work. The problem was the dropdownParent element I was using. I had it set to the modal. Setting it to the immediate parent element and it worked as expected.

routerLinkActive id coupled with [ngClass]

Below web-link demonstrates the routerLinkActive id working when used as a boolean value for a distinct HTML element' [ngClass]
https://stackblitz.com/edit/routerlinkactivesimple?file=src%2Fapp%2Fapp.module.ts
In contrast the routerLinkActive id is not working with #angular/material instance below web-link, but the error disappears by commenting lines 5 and 6 , however not rectifying the usability of routerLinkActive id:
https://stackblitz.com/edit/mat-routerlinkactive?file=src%2Fapp%2Fnav%2Fnav.component.html
your second link has a lot of issues, the app-nav is not even used, so "commenting lines" is not enough to make it work..
but anyway
there is no issue with routerLinkActive, the problem is :
<button mat-button color="white" fxHide.xs *ngIf="true">
<span>
<a routerLink="city-list" routerLinkActive="active-link citNgClassList" #rla_clist="routerLinkActive"
[routerLinkActiveOptions]="{exact: true}">
<mat-icon class="mr">maps_home_work</mat-icon>
Cities
</a>
</span>
</button>
your link is inside a button..
remove the button, keep the "a" and it works
and what's the point of *ngIf="true" ?
Edit :
you can keep the button and remove the 'a' if you want to keep the button style (but it's bad usability wise to display link as button..), just put routerLink, routerLinkActive & routerLinkActiveOption on the button directly
Thanks, JiBi , for your observations. Indeed stripping off the material button wrapper of the links does not longer gives an error on the second StackBlitz link line 5 span , but it hurts to the over all page with styling in a bad way that breaks the harmony of the page that is not easy to substitute. I have removed some of the comments , that were left in place to give an easy idea of what I have tried.
The *ngIf= "true" of the buttons was meant to be a *ngIf= "!rla_clist" or *ngIf= "!rla_cform" so the button sender to the link will not displayed if I am on the link itself ,.....but this is another problem of which better solution I am awaiting.

Testing a vuetify on rails project with capybara selenium

I often use this site but it had never happened to me to ask a question. Now I am blocked and so it is time to ask the first one.
I need to test a sign up form created with vue 2 and vuetify, server side rendered with ruby on rails, webpack 5.
I configured capybara with selenium chrome headless driver, it works when it comes to interacting with text fields and buttons but when I try to check the checkbox:
(byebug) check('Accept')
*** Capybara::ElementNotFound Exception: Unable to find visible checkbox "Accept" that is not disabled
Vuetify hides the input and replaces it with beautiful div but, what is the best approach to check a v-checkbox?
Signup form
If I add the visible attribute, the input is found but nothing happens. I think I need to interact with some other element?
(byebug) check('Accept', visible: false)
#<Capybara::Node::Element tag="input" path="/HTML/BODY[1]/DIV[1]/DIV[1]/DIV[1]/MAIN[1]/DIV[1]/DIV[2]/DIV[1]/DIV[1]/DIV[1]/FORM[1]/DIV[2]/DIV[2]/DIV[1]/DIV[1]/DIV[1]/INPUT[1]">
I also tried this but still nothing happen:
(byebug) page.find('input[type=checkbox]', visible: false).set(true)
#<Capybara::Node::Element tag="input" path="/HTML/BODY[1]/DIV[1]/DIV[1]/DIV[1]/MAIN[1]/DIV[1]/DIV[2]/DIV[1]/DIV[1]/DIV[1]/FORM[1]/DIV[2]/DIV[2]/DIV[1]/DIV[1]/DIV[1]/INPUT[1]">
So I also tried the click way but getting this error:
(byebug) page.find('input[type=checkbox]', visible: false).click
*** Selenium::WebDriver::Error::ElementClickInterceptedError Exception: element click intercepted: Element <input aria-checked="false" id="input-96" role="checkbox" type="checkbox" value=""> is not clickable at point (234, 531). Other element would receive the click: <div class="v-input--selection-controls__ripple"></div>
(Session info: headless chrome=85.0.4183.121)
I tried also executing the raw script:
page.execute_script("window.uiApp.$data.terms_and_conditions = true")
The vue app is mounted in this way:
window.uiApp = new Vue({
i18n,
vuetify,
store,
router,
el: id,
render: h => h(App, {
props
})
})
But window.uiApp.$data is empty, so this attempt also seems to fail :( How to access vue component data (without vue web tool)?
I don't know what else to try, thanks in advance
Looking at the HTML shown in your linked image (in the future when asking questions it would be helpful if you included the relevant HTML directly in your question) it looks like you have a label associated with the hidden checkbox that the user can click. In that case you can use
check('Accept', allow_label_click: true)
which, when the actual checkbox is hidden, will click on the associated label instead. If you want that behavior to be on by default you can set Capybara.automatic_label_click = true.
Your other option is to determine exactly which element is actually being shown as the 'checkbox' and use find(...).click to locate that element and click on it.
I changed the checkbox in this way:
<v-checkbox v-model="terms_and_conditions"
#input='$v.terms_and_conditions.$touch()'
#blur='$v.terms_and_conditions.$touch()'
:label="$t('commons.accept')">
</v-checkbox>
<div class="ml-2">
<v-tooltip bottom>
<template v-slot:activator="{ on }">
<a
target="_blank"
href="/users/terms_and_conditions"
#click.stop
v-on="on"
>
{{ $t('session.sign_up.terms') }}
</a>
</template>
{{ $t('session.sign_up.terms_hint') }}
</v-tooltip>
</div>
Thank you

md-autocomplete in angular material - how to keep the class "md-not-found"

The md-autocomplete provides a class named md-not-found in the md-virtual-repeat-container when you are trying to search for an element that does not exist in the dropdown, displaying an error message underneath. When you remove focus from the input element, the md-not-found is removed. The autocomplete therefore gives a false impression of having a valid input, as the user is not presented with any feedback.
Is there any way to keep the class "md-not-found", even after you unfocus the input element?
md-autocomplete official demo: https://material.angularjs.org/latest/demo/autocomplete
Update
I have made a temporary solution:
<label class="{{selectedItem !== null || searchText === '' ? '' : 'label-error'}}">Name</label>
The label-error class applies a red color.
The solution is not an answer to the question per se, but offers an alternative quick fix
I used md-autocomplete inside the md-chips and its working as well as you want.
When request return noContent(204) md-not-found is being visible and it isn't disappear until user start texting again.
<md-content layout="column">
<md-chips
class="md-input"
ng-model="myItem"
md-autocomplete-snap
md-on-add="change()"
md-on-remove="change()"
required
md-require-match="true"
md-transform-chip="reformr($chip)"
md-separator-keys="keys">
<md-autocomplete md-selected-item="selectedItem"
md-no-cache="true"
md-search-text="search.text"
md-items="item in getSuggestedItems()"
md-item-text="item.name"
md-min-length="0"
placeholder="{{ 'textItemName' | translate }}"
required
md-input-name="suggestedItem"
md-search-text-change="listSuggestedItems(search.text)">
<span md-highlight-text="search.text" md-highlight-flags="^i">{{item.name}}</span>
<md-not-found>
{{'no_item_found' | translate}}
</md-not-found>
</md-autocomplete>
</md-content>

Configure xforms:select element for 'view' mode

I have next problem, when user looks to the filled form element xforms:select shown as it should be readonly and displays the label of selected item, below is html represenation of the element as it comes to browser
...
<span
id="control-8-control"
class="xforms-control xforms-select xforms-incremental xforms-select-appearance-full xforms-static xforms-readonly"
>
some value1
</span>
...
, but when user clicks on the text "some value", this texts turns to value of selected item, and looks next way
...
<span
id="control-8-control"
class="xforms-control xforms-select xforms-incremental xforms-select-appearance-full xforms-static xforms-readonly"
>
2WPbzcoW3eoH/1rDCyejaA==
</span>
...
Obviously some listener is hanging on that element, and changes it's inner-html.
Moreover this behavior can be observed only for xforms:select elements with appearance="full"
Where can I reconfigure this element behavior?
This is a bug. I didn't reproduce exactly the same problem you had, as I have been testing this on a nightly build, but most likely, the source of the problem is the same: the client sends a value change to the server when you click on the label, while it shouldn't. I fixed this, and the fix will be in the next nightly build. For reference, this is the bug and commit.

Resources