1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 07:43:35 +00:00

[PS-1301] Accessibility: improve item edit for URIs and custom fields (#3305)

* Add `role="group"` and accName to URI and custom field groups (browser)

Provides more context when editing fields (to understand what the remove, options, etc buttons are all about)

* Add `aria-describedby` to custom field value fields (browser)

provides further context other than the generic "Value" label

* Add `role="group"` and accName to URI and custom field groups, add `aria-describedby` to custom field value fields (desktop)

* Add `role="group"` and accName to URI and custom field groups, add `aria-describedby` to custom field value fields (web)

* Use `attr.aria-label` instead of `appA11yTitle`

don't need/want the tooltips appearing everywhere
This commit is contained in:
Patrick H. Lauke
2022-08-19 13:17:20 +01:00
committed by GitHub
parent c53ed9956e
commit a48bf9269f
6 changed files with 25 additions and 0 deletions

View File

@@ -6,11 +6,13 @@
<!-- Current custom fields --> <!-- Current custom fields -->
<div cdkDropList (cdkDropListDropped)="drop($event)" *ngIf="cipher.hasFields"> <div cdkDropList (cdkDropListDropped)="drop($event)" *ngIf="cipher.hasFields">
<div <div
role="group"
class="box-content-row box-content-row-multi box-draggable-row" class="box-content-row box-content-row-multi box-draggable-row"
appBoxRow appBoxRow
cdkDrag cdkDrag
*ngFor="let f of cipher.fields; let i = index; trackBy: trackByFunction" *ngFor="let f of cipher.fields; let i = index; trackBy: trackByFunction"
[ngClass]="{ 'box-content-row-checkbox': f.type === fieldType.Boolean }" [ngClass]="{ 'box-content-row-checkbox': f.type === fieldType.Boolean }"
attr.aria-label="{{ f.name }}"
> >
<button <button
type="button" type="button"
@@ -41,6 +43,7 @@
*ngIf="f.type === fieldType.Text" *ngIf="f.type === fieldType.Text"
placeholder="{{ 'value' | i18n }}" placeholder="{{ 'value' | i18n }}"
appInputVerbatim appInputVerbatim
attr.aria-describedby="fieldName{{ i }}"
/> />
<!-- Hidden --> <!-- Hidden -->
<input <input
@@ -53,6 +56,7 @@
*ngIf="f.type === fieldType.Hidden" *ngIf="f.type === fieldType.Hidden"
placeholder="{{ 'value' | i18n }}" placeholder="{{ 'value' | i18n }}"
[disabled]="!cipher.viewPassword && !f.newField" [disabled]="!cipher.viewPassword && !f.newField"
attr.aria-describedby="fieldName{{ i }}"
/> />
<!-- Linked --> <!-- Linked -->
<select <select
@@ -60,6 +64,7 @@
name="Field.Value{{ i }}" name="Field.Value{{ i }}"
[(ngModel)]="f.linkedId" [(ngModel)]="f.linkedId"
*ngIf="f.type === fieldType.Linked && cipher.linkedFieldOptions != null" *ngIf="f.type === fieldType.Linked && cipher.linkedFieldOptions != null"
attr.aria-describedby="fieldName{{ i }}"
> >
<option *ngFor="let o of linkedFieldOptions" [ngValue]="o.value">{{ o.name }}</option> <option *ngFor="let o of linkedFieldOptions" [ngValue]="o.value">{{ o.name }}</option>
</select> </select>
@@ -74,6 +79,7 @@
appTrueFalseValue appTrueFalseValue
trueValue="true" trueValue="true"
falseValue="false" falseValue="false"
attr.aria-describedby="fieldName{{ i }}"
/> />
<div <div
class="action-buttons" class="action-buttons"

View File

@@ -402,9 +402,11 @@
<div class="box-content"> <div class="box-content">
<ng-container *ngIf="cipher.login.hasUris"> <ng-container *ngIf="cipher.login.hasUris">
<div <div
role="group"
class="box-content-row box-content-row-multi" class="box-content-row box-content-row-multi"
appBoxRow appBoxRow
*ngFor="let u of cipher.login.uris; let i = index; trackBy: trackByFunction" *ngFor="let u of cipher.login.uris; let i = index; trackBy: trackByFunction"
attr.aria-label="{{ 'uriPosition' | i18n: i + 1 }}"
> >
<button <button
type="button" type="button"

View File

@@ -5,10 +5,12 @@
<div class="box-content"> <div class="box-content">
<div cdkDropList (cdkDropListDropped)="drop($event)" *ngIf="cipher.hasFields"> <div cdkDropList (cdkDropListDropped)="drop($event)" *ngIf="cipher.hasFields">
<div <div
role="group"
class="box-content-row box-content-row-multi box-draggable-row" class="box-content-row box-content-row-multi box-draggable-row"
cdkDrag cdkDrag
*ngFor="let f of cipher.fields; let i = index; trackBy: trackByFunction" *ngFor="let f of cipher.fields; let i = index; trackBy: trackByFunction"
[ngClass]="{ 'box-content-row-checkbox': f.type === fieldType.Boolean }" [ngClass]="{ 'box-content-row-checkbox': f.type === fieldType.Boolean }"
attr.aria-label="{{ f.name }}"
> >
<button <button
type="button" type="button"
@@ -39,6 +41,7 @@
*ngIf="f.type === fieldType.Text" *ngIf="f.type === fieldType.Text"
placeholder="{{ 'value' | i18n }}" placeholder="{{ 'value' | i18n }}"
appInputVerbatim appInputVerbatim
attr.aria-describedby="fieldName{{ i }}"
/> />
<!-- Password --> <!-- Password -->
<input <input
@@ -51,6 +54,7 @@
placeholder="{{ 'value' | i18n }}" placeholder="{{ 'value' | i18n }}"
[disabled]="!cipher.viewPassword && !f.newField" [disabled]="!cipher.viewPassword && !f.newField"
appInputVerbatim appInputVerbatim
attr.aria-describedby="fieldName{{ i }}"
/> />
<!-- Linked --> <!-- Linked -->
<select <select
@@ -58,6 +62,7 @@
name="Field.Value{{ i }}" name="Field.Value{{ i }}"
[(ngModel)]="f.linkedId" [(ngModel)]="f.linkedId"
*ngIf="f.type === fieldType.Linked && cipher.linkedFieldOptions != null" *ngIf="f.type === fieldType.Linked && cipher.linkedFieldOptions != null"
attr.aria-describedby="fieldName{{ i }}"
> >
<option *ngFor="let o of linkedFieldOptions" [ngValue]="o.value">{{ o.name }}</option> <option *ngFor="let o of linkedFieldOptions" [ngValue]="o.value">{{ o.name }}</option>
</select> </select>
@@ -72,6 +77,7 @@
appTrueFalseValue appTrueFalseValue
trueValue="true" trueValue="true"
falseValue="false" falseValue="false"
attr.aria-describedby="fieldName{{ i }}"
/> />
<div <div
class="action-buttons" class="action-buttons"
@@ -84,6 +90,7 @@
appA11yTitle="{{ 'toggleVisibility' | i18n }}" appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="f.showValue" [attr.aria-pressed]="f.showValue"
(click)="toggleFieldValue(f)" (click)="toggleFieldValue(f)"
attr.aria-describedby="fieldName{{ i }}"
> >
<i <i
class="bwi bwi-lg" class="bwi bwi-lg"

View File

@@ -391,9 +391,11 @@
<div class="box-content"> <div class="box-content">
<ng-container *ngIf="cipher.login.hasUris"> <ng-container *ngIf="cipher.login.hasUris">
<div <div
role="group"
class="box-content-row box-content-row-multi" class="box-content-row box-content-row-multi"
appBoxRow appBoxRow
*ngFor="let u of cipher.login.uris; let i = index; trackBy: trackByFunction" *ngFor="let u of cipher.login.uris; let i = index; trackBy: trackByFunction"
attr.aria-label="{{ 'uriPosition' | i18n: i + 1 }}"
> >
<button <button
type="button" type="button"

View File

@@ -2,9 +2,11 @@
<h3 class="mt-4">{{ "customFields" | i18n }}</h3> <h3 class="mt-4">{{ "customFields" | i18n }}</h3>
<div cdkDropList (cdkDropListDropped)="drop($event)" *ngIf="cipher.hasFields"> <div cdkDropList (cdkDropListDropped)="drop($event)" *ngIf="cipher.hasFields">
<div <div
role="group"
class="row" class="row"
cdkDrag cdkDrag
*ngFor="let f of cipher.fields; let i = index; trackBy: trackByFunction" *ngFor="let f of cipher.fields; let i = index; trackBy: trackByFunction"
attr.aria-label="{{ f.name }}"
> >
<div class="col-5 form-group"> <div class="col-5 form-group">
<div class="d-flex"> <div class="d-flex">
@@ -42,6 +44,7 @@
[(ngModel)]="f.value" [(ngModel)]="f.value"
appInputVerbatim appInputVerbatim
[disabled]="cipher.isDeleted || viewOnly" [disabled]="cipher.isDeleted || viewOnly"
attr.aria-describedby="fieldName{{ i }}"
/> />
<div class="input-group-append"> <div class="input-group-append">
<button <button
@@ -65,6 +68,7 @@
appInputVerbatim appInputVerbatim
autocomplete="new-password" autocomplete="new-password"
[disabled]="cipher.isDeleted || viewOnly || (!cipher.viewPassword && !f.newField)" [disabled]="cipher.isDeleted || viewOnly || (!cipher.viewPassword && !f.newField)"
attr.aria-describedby="fieldName{{ i }}"
/> />
<div class="input-group-append"> <div class="input-group-append">
<button <button
@@ -101,6 +105,7 @@
[(ngModel)]="f.linkedId" [(ngModel)]="f.linkedId"
*ngIf="f.type === fieldType.Linked && cipher.linkedFieldOptions != null" *ngIf="f.type === fieldType.Linked && cipher.linkedFieldOptions != null"
[disabled]="cipher.isDeleted || viewOnly" [disabled]="cipher.isDeleted || viewOnly"
attr.aria-describedby="fieldName{{ i }}"
> >
<option *ngFor="let o of linkedFieldOptions" [ngValue]="o.value">{{ o.name }}</option> <option *ngFor="let o of linkedFieldOptions" [ngValue]="o.value">{{ o.name }}</option>
</select> </select>
@@ -117,6 +122,7 @@
trueValue="true" trueValue="true"
falseValue="false" falseValue="false"
[disabled]="cipher.isDeleted || viewOnly" [disabled]="cipher.isDeleted || viewOnly"
attr.aria-describedby="fieldName{{ i }}"
/> />
</div> </div>
<button <button

View File

@@ -273,8 +273,10 @@
</div> </div>
<ng-container *ngIf="cipher.login.hasUris"> <ng-container *ngIf="cipher.login.hasUris">
<div <div
role="group"
class="row" class="row"
*ngFor="let u of cipher.login.uris; let i = index; trackBy: trackByFunction" *ngFor="let u of cipher.login.uris; let i = index; trackBy: trackByFunction"
attr.aria-label="{{ 'uriPosition' | i18n: i + 1 }}"
> >
<div class="col-7 form-group"> <div class="col-7 form-group">
<label for="loginUri{{ i }}">{{ "uriPosition" | i18n: i + 1 }}</label> <label for="loginUri{{ i }}">{{ "uriPosition" | i18n: i + 1 }}</label>