ClickHouse / ClickHouse/click-ui

IconButton hard-codes aria-label to the icon name and ignores a consumer-provided aria-label

Open Beginner friendly
#1,056 0 comments 0 reactions 0 assignees View on GitHub
a11y bug
Dominant language
TypeScript
Stars
135
Forks
33
Avg merge
2d 13h
Merged PRs (30d)
19

Description

## Summary

`IconButton` sets `aria-label` to the **raw icon token name** (e.g. `sparkle`, `trash`, `cross`) and there is no way to override it. Because `aria-label={iconName}` is placed **after** the `{...props}` spread, a consumer-supplied `aria-label` is silently clobbered. This means every `IconButton` exposes a non-human-meaningful accessible name to screen-reader users, with no escape hatch.

## Current behavior

`src/components/IconButton/IconButton.tsx` (on `main`):

```tsx
export const IconButton = forwardRef(
({ type = 'primary', icon, size, disabled, className, ...props }, ref) => {
const iconName = icon ? icon.toString() : 'unknown icon';

return (



);
}
);
```

Two distinct problems:

1. **Poor default accessible name.** With no label provided, the accessible name falls back to the icon token (`"sparkle"`, `"trash"`, …), which is meaningless to assistive-tech users describing the *action*. Unlike `Button`, `IconButton` has no `label`/`ariaLabel` prop.
2. **The default can't be overridden.** `IconButtonProps extends HTMLAttributes`, so the type advertises `aria-label` as a valid prop, but the implementation ignores it at runtime (it's spread first, then overwritten). The only override that currently survives is `aria-labelledby` (spread via `...props`, and per the accessible-name spec it outranks `aria-label`) — which requires a referenced DOM node and is non-obvious.

This is a type/runtime contract mismatch, not just a styling default — which is why I'd classify it as a bug rather than an enhancement.

## Expected behavior

A consumer-provided accessible name should win, and there should be an explicit, discoverable way to set one.

## Suggested fix (small, backward-compatible)

Respect a consumer-provided `aria-label`, falling back to the icon name only when none is given:

```tsx

```

and/or add an explicit `label` prop mirroring `Button`:

```tsx
export interface IconButtonProps extends HTMLAttributes {
// ...
/** Accessible name for the button. Falls back to the icon name if omitted. */
label?: string;
}
```

## Impact

Affects every `IconButton` instance. In the control-plane `apps/web` app alone there are ~124 instances, each currently announcing an icon token as its accessible name.

## Environment

- Observed on `@clickhouse/click-ui` `v0.2.1-rc.8` (styled-components implementation) and confirmed still present on `main` (CSS-modules implementation).

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with src/components/IconButton/IconButton.tsx and inspect how props and aria-label are applied to the button. Verify the chosen behavior for a consumer-provided accessible name and the fallback icon name, then add coverage for both cases and confirm existing IconButton behavior remains intact.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
accessibility, frontend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.