elastic / elastic/eui

[Epic] Improve icons

Open
#8,860 9 comments 0 reactions 1 assignee Claimed by @weronikaolejniczak View on GitHub
tech debt
Dominant language
TypeScript
Stars
6.4k
Forks
911
Avg merge
2d 11h
Merged PRs (30d)
65

Description

## ✨ Summary

[EuiIcon](https://eui.elastic.co/docs/components/display/icons/) still causes user-perceivable rendering issues in Kibana (load fade-in → extra document layers). Invalid or removed glyph names fail silently at runtime (``). Closing `IconType` is not the path: it is a consumer-wide type migration and does not fix tree-shaking, layers, or the class-component/cache debt.

**Direction:** ship tree-shakeable icon components in a separate package, migrate Kibana and Cloud UI onto them, then remove icons from `@elastic/eui`. Keep `EuiIcon` only as deprecated compat until that cutover. Unknown *string* names on the old API get an empty placeholder + console warning in the meantime.

## ❗ Problem or Opportunity

### 1. Fade-in loading creates extra document layers

First-load fade-in puts each `EuiIcon` on its own [layer](https://developer.chrome.com/docs/devtools/layers), which slows graphics (not React) re-renders — especially scrollable `EuiDataGrid` (e.g. Alerts). New icon components must not repeat this.

### 2. ~~Not tree-shakeable / webpack-only~~ Partial

`icon_map.ts` uses explicit `() => import('./assets/foo')`. Unused SVGs are code-split; Vite/Rollup/esbuild work ([#5463](https://github.com/elastic/eui/issues/5463), [#7982](https://github.com/elastic/eui/issues/7982), [#7852](https://github.com/elastic/eui/issues/7852)).

String `type` still ships the **full name map** with every `EuiIcon` import. True tree-shaking needs imported components (same idea as `@elastic/eui-illustrations`).

### 3. Invalid glyph names fail silently

`IconType` is `EuiIconType | string | ComponentType`, so `| string` makes the union `string`. `tsc` does not catch typos or removed names. Runtime treats unknown strings as URLs → broken image. ESLint `no-deprecated-icon-aliases` is only `warn` and only known aliases.

Closing `IconType` ([#9940](https://github.com/elastic/eui/issues/9940), closed) was evaluated and **not** taken: ~700 Kibana type errors, TS2590 on button `ExclusiveUnion`, Cloud UI the same class of work. Plugin registries (`euiIconType`, `iconClass`) are runtime strings and would never fully type-check as a closed glyph union.

## 🎯 Value

- DataGrid / Alerts: no extra layers on the new components.
- Unused glyphs drop out of the bundle.
- Missing names fail at **import** (and CI), not as broken ``s.
- Can evolve glyphs (e.g. adaptive color) without fighting `EuiIcon`.

## Urgency

Broken leftover aliases in Kibana are already renamed. No rush to close `IconType`. Runtime empty+warn is the small immediate gap. The package + migration is the real initiative.

## 🧠 Feasibility & Direction

Do **not** rewrite `EuiIcon` in place (class component, cache, `onIconLoad`, string map). New package + new components; deprecate `EuiIcon`; migrate consumers; then delete icons from `@elastic/eui`.

Custom URLs / data URIs / SVG components stay on `EuiIcon` until those call sites have an explicit story (or stay as `` / raw SVG). Glyph *names* move to imported components.

## ❓ Open Questions to answer

- Package name: `@elastic/eui-icons` ([#8909](https://github.com/elastic/eui/issues/8909)) vs `@elastic/eui-glyphs` (thread).
- One `` wrapper vs dedicated `` components (or both).
- Adaptive / CSS-variable glyphs ([kibana#206540](https://github.com/elastic/kibana/pull/206540)) — in scope for the new package, not for `EuiIcon`.
- How long `EuiIcon` stays in `@elastic/eui` after [#9980](https://github.com/elastic/eui/issues/9980); what remains allowed (custom assets only vs full deprecation).

---

## 📐 Definition

### Proposed Solution

1. **[#9967](https://github.com/elastic/eui/issues/9967)** — `EuiIcon`: unknown *glyph-shaped* strings → empty placeholder + `console.error`/`warn`. Do not treat them as ``. Real asset URLs and components unchanged.
2. **[#9979](https://github.com/elastic/eui/issues/9979)** — `no-deprecated-icon-aliases` → `error`; fix remaining hits.
3. **[#8909](https://github.com/elastic/eui/issues/8909)** — `@elastic/eui-icons`: assets + generated components; deprecate `EuiIcon` in favor of imports.
4. **[#9980](https://github.com/elastic/eui/issues/9980)** — Kibana + Cloud UI: codemods / ESLint / agent skills; migrate straightforward `EuiIcon` glyph usage; codeowners for the rest. Starts after `EuiIcon` is deprecated.
5. **[#9981](https://github.com/elastic/eui/issues/9981)** — breaking: remove icon bundling from `@elastic/eui` once consumers are off it; communicate.

Later: escalate remaining string-glyph usage (console + ESLint) to **errors** so new `EuiIcon` glyph usage cannot land.

**Out of scope / closed:** [#9940](https://github.com/elastic/eui/issues/9940) closed `IconType`; [#8910](https://github.com/elastic/eui/issues/8910) `onIconLoad`, [#8911](https://github.com/elastic/eui/issues/8911) FC rewrite, [#8912](https://github.com/elastic/eui/issues/8912) cache — die with old `EuiIcon`, not rewritten in place.

### Acceptance criteria

- [ ] Unknown `EuiIcon` glyph names do not render the browser broken-image icon.
- [ ] Icons are importable, tree-shakeable components from a dedicated package.
- [ ] Kibana and Cloud UI have migrated straightforward glyph usage; remaining cases tracked with owners.
- [ ] `@elastic/eui` no longer ships the icon map/assets (breaking, after migration).
- [ ] Docs: import components, not string `type`, for glyphs.

### Definition of done

Package published, consumers migrated (or explicitly excepted), icons removed from `@elastic/eui`, changelog + upgrade email/docs.

### Documentation needs

Consuming-EUI + Icons docs: new imports, deprecation of string `type` / `EuiIcon` for glyphs, custom asset guidance, upgrade guide for [#9981](https://github.com/elastic/eui/issues/9981).

### Impact scope

Breaking when icons leave `@elastic/eui`. Until then: additive package + deprecation. Kibana and Cloud UI are the migration surface (large, mechanical + some registries/custom renderers).

### Rollout plan

EUI-only 9967 / 9979 → publish icons package + deprecate `EuiIcon` → Kibana/Cloud UI PRs per team → breaking removal. No closed-`IconType` EUI bump as the migration vehicle.

## Goals

1. ~~Refactor EuiIcon to not rely on webpack magic strings~~ Done
2. Switch glyph usage from string `type` to imported components for tree-shaking and valid names in CI
3. Prefer sync component imports; keep async only where needed
4. New components must not use the load fade-in / extra layer

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.