DSingh0304 opened a new issue, #3322:
URL: https://github.com/apache/apisix-dashboard/issues/3322
## Summary
Add dark mode theme support to the APISIX Dashboard, allowing users to
switch between light, dark, and system preferred color schemes. This improves
accessibility, reduces eye strain in low light environments, and aligns the
dashboard with modern UI standards.
## Motivation
- Users frequently work with the dashboard for extended periods; dark mode
reduces eye fatigue
- Many modern admin dashboards (Grafana, Kibana, Cloudflare) offer dark mode
as a standard feature
- System level dark mode preferences (`prefers-color-scheme`) are widely
adopted across OSes
- Improved accessibility and WCAG compliance
## Current Architecture
The dashboard currently uses a **light-only theme** with two UI libraries
running side by side:
| Layer | Library | Usage |
|-------|---------|-------|
| **Layout shell** | Mantine v8 (`@mantine/core`) | `AppShell`, `Header`,
`Navbar`, form inputs (`TextInput`, `Select`, `TagsInput`, etc.), `Modal`,
`Drawer`, `Notifications`, `Button`, `Group` |
| **Data tables** | Ant Design v5 + Pro Components (`antd`,
`@ant-design/pro-components`) | `ProTable` across all list pages (routes,
consumers, upstreams, services, SSLs, secrets, etc.) |
| **Code editor** | Monaco Editor (`@monaco-editor/react`) | JSON/YAML
editing in forms, currently hardcoded to `vs-light` theme |
| **State management** | Jotai (`jotai`) | `atomWithStorage` for persisted
settings (admin key) |
| **Icons** | Unplugin Icons (`@iconify-json/material-symbols`) | Material
Symbols icon set |
| **Styling** | PostCSS with Mantine preset | CSS variables
(`--mantine-color-*`), minimal custom CSS in `global.css` |
### Key observations
- **Mantine** is the primary UI library, it has **first-class dark mode
support** via `MantineProvider` with a `forceColorScheme` or `colorScheme` prop
and a `useMantineColorScheme` hook
- **Ant Design** is used only for `ProTable` , its `ConfigProvider` already
accepts a `theme.algorithm` prop (`theme.darkAlgorithm`) for dark mode
- **Monaco Editor** supports `vs-dark` theme out of the box
- **Jotai** `atomWithStorage` is already used for persistent settings, same
pattern can store the color scheme preference
- Custom CSS in `global.css` already uses Mantine CSS variables
(`--mantine-color-gray-*`), which automatically adapt when Mantine's color
scheme changes
## Implementation Plan
### Phase 1: Theme Infrastructure
**Goal**: Wire up the theme switching mechanism across all three UI layers.
1. **Add color scheme atom** in `src/stores/global.ts`:
- Create a `colorSchemeAtom` using `atomWithStorage` with values `'light'
| 'dark' | 'auto'`
- Default to `'auto'` (respect system preference)
2. **Update `MantineProvider`** in `src/main.tsx`:
- Read the `colorSchemeAtom` value
- Pass `forceColorScheme` (or use `defaultColorScheme` +
`useMantineColorScheme`) to `MantineProvider`
- Mantine components will automatically adapt no per component changes
needed
3. **Update `AntdConfigProvider`** in `src/config/antdConfigProvider.tsx`:
- Conditionally apply `theme.darkAlgorithm` based on the active color
scheme
- This makes all `ProTable` instances dark-mode aware without touching
individual table files
4. **Update Monaco Editor** in `src/components/form/Editor.tsx`:
- Change the hardcoded `theme: 'vs-light'` to dynamically use `'vs-dark'`
when dark mode is active
### Phase 2: Theme Toggle UI
**Goal**: Provide a user-facing control to switch themes.
1. **Create `ThemeToggle` component** in `src/components/Header/`:
- A segmented control or action icon button with three states: Light ☀️ /
Dark 🌙 / Auto 💻
- Uses `useAtom(colorSchemeAtom)` to read/write the preference
- Placed in the header alongside the existing `SettingModalBtn` and
`LanguageMenu`
2. **Update `Header/index.tsx`**:
- Add `<ThemeToggle />` to the right-side `Group`
### Phase 3: Custom CSS Adjustments
**Goal**: Fix any remaining hardcoded colors that don't adapt automatically.
1. **Audit `global.css`**:
- The Monaco editor wrapper uses `--mantine-color-gray-0`,
`--mantine-color-gray-3`, etc. these auto-adapt with Mantine's dark mode
- Verify and fix any remaining hardcoded hex colors
2. **Audit inline styles**:
- Search for any hardcoded color values in `.tsx` files (e.g., `color:
'#xxx'`, `bg="white"`)
- Replace with Mantine color tokens or CSS variables
### Phase 4: Testing & Polish
1. **Visual verification** of all pages in both themes:
- All list pages (routes, services, upstreams, consumers, SSLs, etc.)
- All detail/edit forms
- Settings modal
- Navigation sidebar
- Monaco editor
2. **Contrast** ratio checks (WCAG AA ≥ 4.5:1) using browser DevTools or
Lighthouse
3. **Transition smoothness**: Add CSS transition (`transition:
background-color 0.2s, color 0.2s`) on `body` for a non jarring switch
4. **E2E tests**: Add a basic test to verify theme persistence across page
reloads
## Files to Modify
| File | Change |
|------|--------|
| `src/stores/global.ts` | Add `colorSchemeAtom` with `atomWithStorage` |
| `src/main.tsx` | Wire `colorSchemeAtom` to `MantineProvider` color scheme |
| `src/config/antdConfigProvider.tsx` | Conditionally apply
`theme.darkAlgorithm` |
| `src/components/form/Editor.tsx` | Dynamic Monaco theme (`vs-light` /
`vs-dark`) |
| `src/components/Header/index.tsx` | Add `ThemeToggle` to header |
| `src/styles/global.css` | Audit and fix any hardcoded colors |
## New Files
| File | Purpose |
|------|---------|
| `src/components/Header/ThemeToggle.tsx` | Theme switcher UI component
(Light / Dark / Auto) |
## Why This Is Low Risk
- **Mantine v8** handles dark mode natively most components just work
- **Ant Design v5** `ConfigProvider` dark algorithm is a one line change
- **Monaco** has built in `vs-dark` theme
- The custom CSS is minimal (one file, ~60 lines) and already uses CSS
variables
- State persistence pattern (`atomWithStorage`) is already established in
the codebase
- No structural or architectural changes are needed this is purely additive
## Open Questions
- [ ] Should the default be `auto` (follow system) or `light` (current
behavior)?
- [ ] Preferred toggle UI: segmented control in header, or a dropdown/icon
button?
- [ ] Any specific brand color adjustments for dark mode?
## References
- [Mantine Dark Mode Guide](https://mantine.dev/guides/dark-theme/)
- [Ant Design Dark
Theme](https://ant.design/docs/react/customize-theme#use-dark-theme)
- [Monaco Editor Themes](https://microsoft.github.io/monaco-editor/)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]