Implementation Status
How much of the library is built, and how much each product uses. Per-product details are in the tabs; what is left to migrate, component by component, is on Migration.
How to read these numbers
- Weighted usages:
- Places in the code that still use MUI or @filigran/ui, July vs today.
- Library readiness:
- Share of those places whose library component is already built.
- Components needed:
- Library components a product uses or still needs to switch to.
- Interface elements converted:
- Rendered elements moved to the library, out of those it can replace today.
- In service:
- Library components a product imports and renders today.
- Weight:
- Places across products that a component will replace.
Layout wrappers (Box, Stack, Grid…) are not counted: they become styling utilities, not components.
Library — 52 components planned
Ready for stable: Alert, Avatar, Badge, Banner, Breadcrumbs, Button, Card, CardContent, CardFooter, CardHeader, CardMetaBar, CardSubtitle, CardTitle, Checkbox, ColorPicker, Combobox, CustomizePanel, DatePicker, Dialog, Drawer, FileSelect, Header, Hero, HeroBody, HeroHeader, HeroStat, Input, Menu, Paper, ProgressBar, Radio, RichTextField, Select, Skeleton, Slider, Snackbar, Spinner, Textarea, Thumbnail, TimePicker — every accessibility check passes with no exemption. Promotion stays a human decision (pnpm promote:component <Name>).
Usage — the July scan against today
Legacy uses in July and today, per product. Readiness can fall while a product migrates: what is left then waits on components not built yet.
- July scan, 2026-07-06
- trunks, 2026-10-27
Show as a table
| July 2026-07-06 | trunks, 2026-10-27 | |
|---|---|---|
| OpenCTI | 2,653 | 2,298 |
| OpenAEV | 9,397 | 6,502 |
| XTM CRQ | 3,023 | 455 |
| All products | 15,073 | 9,255 |
- July scan, 2026-07-06
- trunks, 2026-10-27
Not a step back: OpenCTI went from 2,653 legacy places to 2,298 by moving what the library offers. 33.8% of what is left waits on components not built yet — List, DataTable, Accordion, Popover, Separator.
Not a step back: OpenAEV went from 9,397 legacy places to 6,502 by moving what the library offers. 35.0% of what is left waits on components not built yet — List, DataTable, Accordion, Popover, Separator.
Not a step back: XTM CRQ went from 3,023 legacy places to 455 by moving what the library offers. 65.1% of what is left waits on components not built yet — DataTable, Accordion, Popover, Separator.
Show as a table
| July 2026-07-06 | trunks, 2026-10-27 | |
|---|---|---|
| OpenCTI | 71.3% | 66.2% |
| OpenAEV | 76.8% | 65.0% |
| XTM CRQ | 88.4% | 34.9% |
| All products | 78.2% | 63.8% |
Rule: named imports from MUI (icons aside) or @filigran/ui, counted wherever the identifier appears in a front .ts/.tsx/.js/.jsx file. Replayed on the commits read on 2026-07-06, it reproduces process/mui-inventory.json entry for entry. Trunks read: OpenCTI master 5837b6928f · OpenAEV main 8b216f6454 · XTM CRQ main 028a52af4b.
Adoption across the products
Front-end component files (.tsx and .jsx), counted on the product repositories themselves, at three commits: the one before the design-system merge, the merge, and the trunk a user gets today. Generated code and tests are excluded from all three counts, so the percentages share one denominator.
| Product | Commit read | Front files | Rendering the design system | Still importing MUI |
|---|---|---|---|---|
| OpenCTI | before the design-system merge · c44d7ab8ab · 2026-09-08 | 2,163 | 0 (0.0%) | 1,288 (59.5%) |
| OpenCTI | merge of #18117 · 5b9bcf6116 · 2026-09-08 | 2,170 | 304 (14.0%) | 1,232 (56.8%) |
| OpenCTI | master today · 5837b6928f · 2026-10-27 | 2,255 | 355 (15.7%) | 1,274 (56.5%) |
| OpenAEV | before the design-system merge · 262ffec23f · 2026-10-02 | 1,135 | 0 (0.0%) | 866 (76.3%) |
| OpenAEV | merge of #7919 · 8ded09b623 · 2026-10-02 | 1,138 | 550 (48.3%) | 743 (65.3%) |
| OpenAEV | main today · 8b216f6454 · 2026-10-27 | 1,136 | 551 (48.5%) | 740 (65.1%) |
Generated by pnpm scan:products, which reads each product repository read-only. A file counts as rendering the design system as soon as it imports it once — the count says how far the work has spread, never how much of a screen it paints. For that reading, see zone coverage in the product tabs.
Active workstreams
Everything currently claimed or moving in the component roadmap — who owns what, and where it stands. Weight = places across all three products that will use the component once migrated (see “How to read these numbers”).
| Priority | Component | Status | Owner | PR | Weight, July → today |
|---|---|---|---|---|---|
| 1 | Button | doneready for stable | @fimow | #135 | 1,290 → 18 |
| 2 | Icon | done | sandy | #12 | — |
| 3 | Skeleton | doneready for stable | fimow | #264 | 135 → 230 |
| 3 | Tooltip | done | @fimow | #40 | 930 → 298 |
| 4 | IconButton | done | @fimow | #135 | 493 → 14 |
| 5 | Dialog | doneready for stable | sandy | #51 | 1,353 → 1,101 |
| 6 | Drawer | doneready for stable | fimow | #256 | 60 → 33 |
| 7 | Alert | doneready for stable | sandy | #230 | 279 → 381 |
| 7 | Snackbar | doneready for stable | sandy | #230 | 3 → 3 |
| 8 | Badge | doneready for stable | sandy | #215 | 351 → 24 |
| 8 | Checkbox | doneready for stable | sandy | #73 | 80 → 0 |
| 8 | FileSelect | doneready for stable | thibault | #157 | — |
| 8 | Input | doneready for stable | sandy | #224 | 1,804 → 234 |
| 8 | Menu | doneready for stable | sandy | #110 | 979 → 405 |
| 8 | ProgressBar | doneready for stable | sandy | #118 | 19 → 22 |
| 8 | Radio | doneready for stable | sandy | #73 | 44 → 0 |
| 8 | Select | doneready for stable | sandy | #191 | 646 → 0 |
| 8 | Slider | doneready for stable | sandy | #78 | 9 → 6 |
| 8 | Spinner | doneready for stable | sandy | #115 | 32 → 34 |
| 8 | Switch | done | sandy | #135 | 91 → 80 |
| 8 | Textarea | doneready for stable | sandy | #170 | 13 → 0 |
| 9 | Card | doneready for stable | sandy | #144 | 365 → 217 |
| 9 | Combobox | doneready for stable | sandy | #250 | 117 → 10 |
| 10 | Chip | done | sandy | #192 | 177 → 14 |
| 10 | Paper | doneready for stable | sandy | #121 | 312 → 65 |
| 11 | Breadcrumbs | doneready for stable | sandy | #152 | 17 → 0 |
| 11 | Hero | doneready for stable | sandy | #232 | — |
| 14 | Avatar | doneready for stable | fimow | #251 | 71 → 61 |
| 16 | ButtonGroup | done | sandy | #229 | 91 → 107 |
| 17 | Typography | done | sandy | #44 | 1,753 → 2,469 |
| 18 | SearchField | done | sandy | #189 | — |
| 21 | Banner | doneready for stable | thibault | #252 | — |
| 23 | Header | doneready for stable | sandy | #189 | 30 → 29 |
| 24 | Navbar | done | sandy | #107 | — |
| — | ColorPicker | doneready for stable | @fimow | #173 | — |
| — | CustomizePanel | doneready for stable | surbhi | #247 | — |
| — | DatePicker | doneready for stable | sandy | #241 | 40 → 24 |
| — | HeroStat | in reviewready for stable | fimow | #275 | — |
| — | MarkdownField | done | @fimow | #257 | — |
| — | NavbarItem | done | sandy | #123 | — |
| — | NavbarSubmenu | done | sandy | #123 | — |
| — | ProductSwitcher | done | sandy | #111 | — |
| — | RichTextField | in reviewready for stable | @fimow | #270 | — |
| — | Tabs | done | sandy | #135 | 191 → 27 |
| — | TimePicker | doneready for stable | sandy | #241 | 7 → 3 |
Tracks
Axes not tied to a single component or product — release machinery, the visual-coherence harness, and other foundations work (process/FOUNDATIONS-REPORT.md §6, process/AI-BACKLOG.md).
| Track | Status | Owner |
|---|---|---|
| check-figma-fidelity.ts hardening — verification of computed font-weight | in review | sandy |
| Missing mono Named Style in theme.css | to do | thibault |
| Eradication of inline styles outside the system + CI gate (style={{}} blind spot in check:tokens) | in progress | sandy |
| Viewport safety net on the w-overlay-* utilities (single-subject fix) | done | sandy |
| Package entry ships every component's *.meta.ts — ~3x the runtime cost per component | to do | — |
| Sync ROADMAP post-merges (#43 Navbar family, #44 Text) + desync catch-up (#40 Tooltip/IconButton, #41 SearchField) + batch evaluation of /status promotions | in progress | sandy |
| S3 — Per-product consumer integration kit | in progress | sandy |
| S5 — Release machinery (npm publishing) | in review | olivier |
| S6 — Visual coherence harness (Playwright) | in progress | sandy |
| S8 — @filigran/ui deprecation plan (XTM CRQ) | to do | — |
| Scaffolding — contrastPairs checklist by state × variant + Rule 5 gate | in review | sandy |
| Spacing & color enforcement via the theme (lint as last resort) | to do | — |
V2 / deferred — decided, not forgotten
Everything the project has deliberately pushed to a later version. Each entry says what it is, where its absence is felt today, what event retires it, and where the decision is written down. This is the one part of the page that is not generated: a deferral is a decision taken in a product’s feedback file, an RFC or an arbitration, and three of these do not exist in the roadmap at all — see lib/deferred.ts for why, and for the upkeep rule.
Sorted by reach today — occurrences summed across the three products, the same measure as “weighted usages” above, or sites counted by hand for a sub-feature. Reach is not urgency: an entry flagged blocking a migration today holds a dated exemption in a product’s own MUI guard, so a migration is held open right now whatever its count says.
Segmented control (ButtonGroup / ToggleButtonGroup)
blocking a migration today107 usages across the products today, 91 in JulyA group of two or three buttons where exactly one is selected at a time — OpenCTI's search bar uses it to switch between advanced search, bulk search and natural-language search. The COMPONENT is no longer what is missing (see removalCondition): these are the call sites that have not converted yet.
- Where it is missing
- OpenAEV (73 today, 70 in July) — admin/components, components/common — ToggleButton + ToggleButtonGroupOpenCTI (34 today, 21 in July) — opencti-front/src/components/SearchInput.jsx — the top bar's mode toggles, plus ViewSwitchingButtons.tsx, dataGrid, fields
- Retires when
- HALF MET as of 2026-08-30, and the entry stays until the other half lands. The library half is DONE: ButtonGroup ships, owns exclusivity, roving focus and the selected style, and gained `asChild` in PR #193 (bd57527) so a segment can be a router link. What remains is the product half this condition also names — the OpenCTI header pilot deleting both survivors from TopBar.libraryOnly.test.ts's named list. Verified not done at origin/design-system/current: SearchInput.jsx still imports ToggleButton and ToggleButtonGroup from MUI for the bar's own mode toggles. Delete this entry when that import is gone, per the register's rule that an entry is removed when its condition is met and never marked done.
- Where it is written down
- OpenCTI fds-migration/LIBRARY-FEEDBACK.md #24, measured at pin 35a4768 — the last non-glyph MUI left in the bar, with the group's geometry and semantics measured so the component can be specified. CORRECTED 2026-08-30: this line used to end "ROADMAP.json tracks it as ButtonGroup (priority 16, todo)", which was true when written and is now false twice over — the component shipped and its ROADMAP row is `done` at PR #193. The entry is kept, and re-scoped above, because the sites it counts are still on MUI: OpenCTI adopted ButtonGroup in ViewSwitchingButtons.tsx (adoption `partial`), not in SearchInput.jsx.
Popover
blocking a migration today37 usages across the products today, 37 in JulyA floating panel anchored to a control that holds arbitrary content — not a list of commands (that is Menu) and not a modal (that is Dialog). The library builds one internally to position Combobox, but does not export it.
- Where it is missing
- OpenAEV (24 today, 21 in July) — openaev-front/src/admin/components/nav/BulkOperationsIndicator.tsx — the bulk-operations panel, plus components/common and both colour pickersOpenCTI (3 today, 10 in July) — private/components — and the NLQ dropdown in the top bar, which MUI draws with oneXTM CRQ (10 today, 6 in July) — features/notifications, components/layout — on @filigran/ui
- Retires when
- Popover, PopoverTrigger and PopoverContent resolve from the built entry point. Both products then delete their dated exemption and their guard reddens until the panel is rebuilt — which is the point of having filed it that way.
- Where it is written down
- OpenAEV fds-migration/LIBRARY-FEEDBACK.md #22 (the only item still open there) and OpenCTI #24 “The Popover that comes with it”, exempted by Sandy on 2026-08-13. Verified at pin 35a4768 against the installed build, not a changelog: PR #105's primitive stays internal to Combobox. ROADMAP.json tracks it since 2026-10-27 (priority 4, todo), and process/mui-crosswalk.json maps MUI Popover and Popper onto it.
Separator (generic) — MUI Divider
29 usages across the products today, 39 in JulyA standalone horizontal or vertical rule, usable anywhere. The library has three separators today — NavbarSeparator, MenuSeparator, SelectSeparator — and each is welded to its own component.
- Where it is missing
- OpenAEV (27 today, 29 in July) — admin/components, components/commonOpenCTI (2 today, 10 in July) — private/components
- Retires when
- A standalone Separator ships. Note that the case both pilots originally raised — the rule between a header's two action clusters — is ALREADY closed, by HeaderGroup separatorBefore (library PR #117): what remains deferred is the general-purpose component for the divider sites that are not header clusters.
- Where it is written down
- OpenCTI fds-migration/LIBRARY-FEEDBACK.md #18 and OpenAEV #22 (same ask, raised independently). ROADMAP.json (priority 20, todo, figmaDesigned: true); process/mui-crosswalk.json maps MUI Divider onto this entry.
Snackbar viewport — the Figma frame, not the behaviour
2 sites, counted by handWhere a transient message appears on screen, how several stack, and how they enter and leave. RE-SCOPED 2026-09-19: the BEHAVIOUR now ships — Snackbar is built on @radix-ui/react-toast, with a provider, a portalled viewport placed 24px from the top and right of the window, a timer that pauses on hover and focus, swipe-to-dismiss and the F8 hotkey. What is still owed is the DESIGN: no Figma frame draws the viewport, so its placement (24px from the top and right) and its motion (a 220ms/160ms slide following MUI's Slide) are chosen values recorded in the RFC rather than read off a node.
- Where it is missing
- OpenCTI (1) — opencti-front/src/components/Message.tsx — the MUI Snackbar wrapper this now replaces; unblocked, not yet convertedOpenAEV (1) — openaev-front/src/components/Message.jsx — same wrapper, same state
- Retires when
- A Figma frame draws the viewport — placement, stacking order, entry and exit motion — and src/styles/motion.css is re-derived from it instead of from the defaults chosen here. The product half is no longer part of this condition: both wrappers can be deleted today, and when they are, that is ordinary migration progress rather than this entry's removal.
- Where it is written down
- Snackbar.rfc.md section 3.6 (Known Figma gaps) and section 4.6, which records the measurement behind the portal. SUPERSEDES the 2026-09-18 entry that deferred the behaviour itself: the design lead arbitrated on 2026-09-19 to take the Radix dependency in the same PR, so only the design gap survives.
ProgressBar buffer variant
2 sites, counted by handA second, paler bar behind the first, showing how much is loaded ahead of what has been processed — MUI's valueBuffer.
- Where it is missing
- OpenCTI (2) — the two upload dialogs — and both pass a “current + 10” placeholder rather than a real buffered value
- Retires when
- A design decision on what a second bar behind the first should look like, and at least one site with a real buffered value to justify it — today both sites would draw a fabricated number.
- Where it is written down
- ProgressBar.rfc.md §7 and Q10.
Indeterminate linear bar
1 site, counted by handThe sliding stripe a progress bar shows when the work has no measurable percentage. Its circular twin already exists as Spinner; the linear one does not.
- Where it is missing
- OpenCTI (1) — GraphToolbar — the only indeterminate linear bar
- Retires when
- The sliding animation needs a new @keyframes in theme.css, which sits OUTSIDE the @utility zone agents may edit (AGENTS.md) — so this needs a token delivery from the Figma export pipeline, not a component change.
- Where it is written down
- ProgressBar.rfc.md §7 and Q6.
ProgressBar tone=“warning”
no usage to migrate yetThe orange status colour for a determinate progress bar, alongside the default, success and error tones that shipped.
- Where it is missing
- OpenAEV — admin/components/nav/BulkOperationsIndicator.tsx — nothing there needs warning today, but a fourth status would fall back to the default rather than borrow a neighbouring colour
- Retires when
- A token decision by Sandy. This is BLOCKED ON THE TOKENS, not on the component: --color-feedback-warning-primary (#e6700f) clears WCAG 1.4.11's 3:1 against no track token in theme.css in light mode — 2.51:1 even against its own 30% companion, the construction that carried success and error over the line. Shipping it would be a known accessibility failure, which AGENTS.md forbids outright.
- Where it is written down
- ProgressBar.rfc.md §7 and Q11/Q12 (measured, then re-measured); ROADMAP.json's ProgressBar notes record the escalation to Sandy.