Skip to content

kyverno: dashboard charts lack programmatic labels and namespace data for screen readers #1183

Description

@nyxsky404

Summary

The Kyverno overview dashboard renders two pie charts and a stacked namespace bar chart, but their data is not exposed consistently or with sufficient context to assistive technology.

  • The two pie charts place keyboard focus on a roleless <g> whose derived text is a concatenation such as Pass: 5Fail: 2Warn: 1Error: 1. The focus target is not programmatically associated with the visible chart heading, and the four sector paths are unnamed role="img" nodes.
  • The namespace bar chart has no focusable or semantic data nodes. Its accessibility tree contains only namespace names, numeric axis ticks and the legend. The actual per-namespace pass/fail values are missing.
  • All three primary SVGs have no role, accessible name, aria-labelledby or aria-describedby; their generated <title> and <desc> elements are empty.

As a result, a screen-reader user cannot identify the focused pie chart from the chart itself, and cannot recover the relationships represented by the namespace chart at all.

Environment

  • Repository: headlamp-k8s/plugins
  • Verified on upstream commit: cef63c4dbab7443f5a0568aab5598407ea3d64c6
  • Branch inspected and built: main
  • Still reproducible on upstream: Yes
  • Kyverno plugin package: 0.1.0
  • Recharts: 2.15.4
  • Headlamp Desktop: 0.44.0
  • Electron / Chromium: 38.8.6 / 140.0.7339.249
  • macOS: 26.5.2 (arm64)
  • Kubernetes: kind v1.36.1
  • Kyverno API data: v1.18.2 CRDs with valid wgpolicyk8s.io/v1alpha2 PolicyReport objects

Steps to reproduce

  1. Run Headlamp with the Kyverno plugin built from the commit above.
  2. Connect to a cluster with Kyverno PolicyReport data in multiple namespaces.
  3. Open Kyverno → Overview.
  4. Inspect the page with the browser accessibility tree, or navigate through the charts with a keyboard and screen reader.
  5. Compare the accessibility output with the visible chart data.

Actual result

Relevant live accessibility-tree output:

heading "Results by Status"
SvgRoot
  group focusable
    image
    image
    image
    image
    StaticText "Pass: 5"
    StaticText "Fail: 2"
    StaticText "Warn: 1"
    StaticText "Error: 1"

heading "Results by Severity"
SvgRoot
  group focusable
    image
    image
    image
    image
    StaticText "Critical: 1"
    StaticText "High: 3"
    StaticText "Medium: 3"
    StaticText "Low: 2"

heading "Compliance by Namespace (Top 10)"
SvgRoot
  StaticText "production"
  StaticText "staging"
  StaticText "0"
  StaticText "1"
  StaticText "2"
  StaticText "3"
  StaticText "4"

The namespace chart visually rendered these values, which do not appear in the accessibility tree:

Namespace Pass Fail/Error
production 2 2
staging 3 1

DOM inspection of each primary chart SVG also returned:

role=null
tabindex=null
aria-label=null
aria-labelledby=null
aria-describedby=null
title=""
desc=""
Image

Expected result

  • Each chart has a non-empty programmatic name connected to its visible heading and a useful description of what it represents.
  • Status and severity values are announced with clear boundaries and chart context, without unnamed image nodes or duplicate announcements.
  • Namespace, pass and fail/error values are available as structured data, so the relationships do not depend on visual position, bar height or color.
  • Keyboard interaction, if retained, communicates the current data point and value.

Affected code

  • kyverno/src/components/Dashboard.tsx:239-264 — Results by Status pie chart
  • kyverno/src/components/Dashboard.tsx:266-291 — Results by Severity pie chart
  • kyverno/src/components/Dashboard.tsx:338-358 — Compliance by Namespace bar chart
  • kyverno/package-lock.json — Recharts 2.15.4

Permalinks:

  • {statusData.length > 0 && (
    <Grid item xs={12} md={6}>
    <SectionBox title={t('Results by Status')}>
    <ResponsiveContainer width="100%" height={300}>
    <PieChart>
    <Pie
    data={statusData}
    cx="50%"
    cy="50%"
    innerRadius={60}
    outerRadius={100}
    dataKey="value"
    nameKey="name"
    label={({ name, value }) => `${name}: ${value}`}
    >
    {statusData.map((entry, index) => (
    <Cell key={index} fill={entry.color} />
    ))}
    </Pie>
    <Tooltip />
    <Legend />
    </PieChart>
    </ResponsiveContainer>
    </SectionBox>
    </Grid>
    )}
    {severityData.length > 0 && (
    <Grid item xs={12} md={6}>
    <SectionBox title={t('Results by Severity')}>
    <ResponsiveContainer width="100%" height={300}>
    <PieChart>
    <Pie
    data={severityData}
    cx="50%"
    cy="50%"
    innerRadius={60}
    outerRadius={100}
    dataKey="value"
    nameKey="name"
    label={({ name, value }) => `${name}: ${value}`}
    >
    {severityData.map((entry, index) => (
    <Cell key={index} fill={entry.color} />
    ))}
    </Pie>
    <Tooltip />
    <Legend />
    </PieChart>
    </ResponsiveContainer>
    </SectionBox>
    </Grid>
    )}
  • {namespaceData.length > 0 && (
    <Grid item xs={12}>
    <SectionBox title={t('Compliance by Namespace (Top 10)')}>
    <ResponsiveContainer width="100%" height={300}>
    <BarChart data={namespaceData} margin={{ top: 8, right: 16, left: 16, bottom: 8 }}>
    <XAxis dataKey="name" />
    <YAxis allowDecimals={false} />
    <Tooltip />
    <Legend />
    <Bar dataKey="pass" fill={STATUS_COLORS.pass} name={t('Pass')} stackId="a" />
    <Bar
    dataKey="failAndError"
    fill={STATUS_COLORS.fail}
    name={t('Fail/Error')}
    stackId="a"
    />
    </BarChart>
    </ResponsiveContainer>
    </SectionBox>
    </Grid>
    )}

Suggested direction / acceptance criteria

  1. Give every visualization a programmatic name and description connected to its visible heading.
  2. Enable the appropriate Recharts accessibility support where it improves keyboard navigation.
  3. Provide the chart data through a semantic HTML representation, such as a captioned table or a visible "View data" disclosure, especially for the namespace chart.
  4. Avoid duplicate announcements by choosing one primary representation and hiding only the redundant one from assistive technology.
  5. Add DOM tests for non-empty chart names and exact data values, plus a keyboard-navigation test.

Duplicate search and related work

Searched open and closed issues and PRs for:

  • kyverno dashboard accessibility
  • kyverno a11y
  • screen reader chart
  • Recharts accessibility
  • accessibilityLayer
  • PieChart accessibility
  • BarChart accessibility
  • Compliance by Namespace
  • Results by Status

Related but materially different:

No issue or active PR was found that adds accessible chart names or exposes the namespace values.

I would like to work on this after scope is confirmed. Does this overlap with the reserved work in #938, or may it proceed as an independent accessibility fix?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions