Add aria-label to icon-only badges for accessibility

What does this MR do and why?

Add aria-label to icon-only badges for accessibility

This change adds proper aria-label attributes to icon-only GlBadge components to improve accessibility for screen reader users.

Previously, these badges relied on the icon name as a fallback aria-label (e.g., 'merge-request', 'flag', 'bulb', 'archive'). With upcoming changes in GitLab UI, icon-only badges without explicit aria-label will have no label at all.

Changes:

  • Add aria-label to merge request badge in security dashboard
  • Add aria-label to policy violation badge in security dashboard
  • Add aria-label to solution badge in security dashboard
  • Add aria-label to archival badge in vulnerabilities

Changelog: changed

References

Related to gitlab-org/gitlab-services/design.gitlab.com!5370 which will change the behaviour of icon only badges without an aria-label.

gitlab-org/gitlab-services/design.gitlab.com#3197

Screenshots or screen recordings

These are icon-only badges that appear in the Security Dashboard. The visual appearance remains unchanged - this MR only improves screen reader accessibility.

Before After
[Add screenshot] [Add screenshot]

How to set up and validate locally

Where to find these badges in the UI:

Seed a project with vulnerabilities following the docs.

1. Merge Request Badge:

  1. Navigate to Security > Vulnerability Report in a project
  2. Find a vulnerability that has an auto-remediation merge request
  3. The merge request icon badge appears in the vulnerability row

note: this requires conditions I wasn't fully able to determine. Force this to show by applying the following patch

diff --git a/ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_list.vue b/ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_list.vue
index 664f69b0c6f8..025dada1814a 100644
--- a/ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_list.vue
+++ b/ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_list.vue
@@ -130,12 +130,36 @@ export default {
   data() {
     return {
       selectedVulnerabilities: {},
+      fakeMergeRequest: {
+        id: 'gid://gitlab/MergeRequest/123456',
+        iid: '1234',
+        title: 'Fix: Security vulnerability in authentication',
+        webUrl: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/1234',
+        state: 'opened',
+        author: {
+          name: 'John Doe',
+          username: 'johndoe',
+          human: true,
+        },
+      },
     };
   },
   i18n: {
     image: s__('Vulnerability|Image: %{linkStart}%{image}%{linkEnd}'),
   },
   computed: {
+    vulnerabilitiesWithFakeMR() {
+      // Add fake merge request to the first vulnerability for testing
+      if (this.vulnerabilities.length > 0) {
+        return this.vulnerabilities.map((vuln, index) => {
+          if (index === 0) {
+            return { ...vuln, mergeRequest: this.fakeMergeRequest };
+          }
+          return vuln;
+        });
+      }
+      return this.vulnerabilities;
+    },
     displayFields() {
       // Add the checkbox field if the user can use the bulk select feature.
       return this.canAdminVulnerability ? [FIELDS.CHECKBOX, ...this.fields] : this.fields;
@@ -367,7 +391,7 @@ export default {
       class="vulnerability-list"
       :busy="isLoading"
       :fields="displayFields"
-      :items="vulnerabilities"
+      :items="vulnerabilitiesWithFakeMR"
       :thead-class="{
         'below-selection-summary': shouldShowSelectionSummary,
         'gl-bg-default': true,
@@ -539,7 +563,7 @@ export default {
             :data-qa-badge-description="item.title || item.name"
           />
           <ai-fixed-badge v-if="hasAiMergeRequest(item)" />
-          <merge-request-badge v-if="item.mergeRequest" :merge-request="item.mergeRequest" />
+          <merge-request-badge :merge-request="item.mergeRequest" />
           <ai-possible-fp-badge
             v-if="hasAiExperimentSastFpDetection(item)"
             data-testid="false-positive-vulnerability"

2. Policy Violation Badge:

  1. Configure a security policy in warn mode (Security > Policies)
  2. Create a merge request that triggers the policy
  3. The flag icon badge appears next to vulnerabilities that were bypassed

note: this requires security policies set up on GDK. Force this to show by applying the following patch

diff --git a/ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_list.vue b/ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_list.vue
index 664f69b0c6f8..537f3e8896e2 100644
--- a/ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_list.vue
+++ b/ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_list.vue
@@ -567,7 +567,7 @@ export default {
             v-if="hasAiFalsePositiveCheckInProgress(item)"
             :workflow-name="$options.WORKFLOW_NAMES.SAST_FP_DETECTION"
           />
-          <policy-violation-badge v-if="shouldRenderPolicyViolationBadge(item)" />
+          <policy-violation-badge />
         </div>
       </template>
 

3. Solution Badge:

  1. Navigate to Security > Vulnerability Report
  2. Find a vulnerability with an available solution (e.g., dependency update)
  3. The bulb icon badge appears in the vulnerability row

note: this requires AI features set up on GDK. Force this to show by applying the following patch

diff --git a/ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_list.vue b/ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_list.vue
index 664f69b0c6f8..f180987376bb 100644
--- a/ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_list.vue
+++ b/ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_list.vue
@@ -550,7 +550,7 @@ export default {
             v-else-if="item.falsePositive"
             data-testid="false-positive-vulnerability"
           />
-          <solution-badge v-if="item.hasRemediations" />
+          <solution-badge />
           <ai-resolution-badge
             v-if="
               item.aiResolutionAvailable &&

4. Archival Badge:

  1. Navigate to a vulnerability detail page
  2. If the vulnerability is scheduled for archival, the archive icon badge appears in the header

note: this requires the feature flag to be turned on and vulnerabilits to be over a certain age. Force this to show by applying the following patch

diff --git a/ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_list.vue b/ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_list.vue
index 664f69b0c6f8..e22f8452a43c 100644
--- a/ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_list.vue
+++ b/ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_list.vue
@@ -130,6 +130,7 @@ export default {
   data() {
     return {
       selectedVulnerabilities: {},
+      fakeArchivalDate: '2025-12-31',
     };
   },
   i18n: {
@@ -522,10 +523,7 @@ export default {
 
       <template #cell(activity)="{ item }">
         <div class="gl-flex gl-justify-end gl-gap-3">
-          <archival-badge
-            v-if="item.archivalInformation && item.archivalInformation.aboutToBeArchived"
-            :expected-date="item.archivalInformation.expectedToBeArchivedOn"
-          />
+          <archival-badge :expected-date="fakeArchivalDate" />
           <resolution-badge
             v-if="item.resolvedOnDefaultBranch"
             data-testid="vulnerability-resolution-badge-content"

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist.

Edited by Dan MH

Merge request reports

Loading