Skip to content

feat: add Auto/Light/Dark theme support (fixes #1702)#2496

Open
kushmunjal1kmkm wants to merge 3 commits into
ipfs:mainfrom
kushmunjal1kmkm:fix-dark-mode
Open

feat: add Auto/Light/Dark theme support (fixes #1702)#2496
kushmunjal1kmkm wants to merge 3 commits into
ipfs:mainfrom
kushmunjal1kmkm:fix-dark-mode

Conversation

@kushmunjal1kmkm

Copy link
Copy Markdown

Fixes #1702

Summary

This adds a three-way theme setting — Auto, Light, and Dark — to ipfs-webui.
Auto follows the OS-level prefers-color-scheme and updates live if the OS
setting changes; Light/Dark are manual overrides, persisted across sessions.

The toggle is available in two places: a compact icon in the top bar for
quick switching, and a full selector on the Settings page.

Why I approached it this way

I know dark mode was attempted once before in #2322 and reverted in #2339
after several screens/modals were found unreadable post-merge. I read through
that history before starting, and tried to design around the specific gap
that caused the revert — rather than hand-editing individual components, I
introduced CSS custom properties for color (--element-bg, --text,
--border-color, etc., swapped per theme via a [data-theme="dark"]
selector) so shared utility classes and components get themed centrally, and
went through every screen and every modal/dropdown/menu I could find, not
just the main page layouts.

What changed

  • ThemeContext/ThemeProvider (src/contexts/theme-context.js) — tracks
    the active theme, listens for OS-level scheme changes when set to Auto,
    persists the user's explicit choice to localStorage.
  • TopBarThemeToggle and ThemeSelector components for switching the theme
    from the top bar and from Settings respectively.
  • Removed hardcoded inline colors across [Box, ProgressBar, SelectedActions,
    FileImportStatus, Breadcrumbs, PublishModal, modal.tsx, App.js header,
    NodeBandwidthChart, Speedometer, WorldMap] in favor of theme-aware CSS
    classes/custom properties.
  • Fixed a pre-existing bug where the Settings page rendered a raw
    themeDescription i18n key instead of translated text.
  • World map on the Peers page uses a CSS filter to invert/desaturate the
    static map image for dark mode rather than shipping a second image asset.

Explicitly out of scope for this PR

The Explore/DAG page's card styling is rendered by the separate
ipld-explorer-components package and needs its own companion PR there
(same pattern as the original #2322 effort) — I'm treating that as a
follow-up rather than bundling it in here, since it's a different repo with
its own release cycle.

Testing

  • [ ✓ ] npm run lint — passing as of <83d9e2b>
  • [ ✓ ] npm run test:unit — passing as of <83d9e2b>
  • [ ✓ ] npm run test:e2e — passing as of <83d9e2b>
  • [ ✓ ] Manually verified every screen (Status, Files, Peers, Settings,
    Diagnostics) plus modals/dropdowns/selection states in both Light and
    Dark, including toggling OS-level dark mode live for Auto
  • [ ✓ ] Confirmed package.json/package-lock.json have no unrelated
    dependency changes

Open questions / things I'd appreciate a second pair of eyes on

  • [Fill in honestly — e.g. "I'm not 100% sure the background prop I'm
    passing into @tableflip/react-dropdown is officially supported by that
    library vs. just being ignored — I confirmed via devtools that it renders
    correctly, but wanted to flag the assumption in case there's a cleaner way."]
  • [Any other genuine uncertainty — better to name it than have a reviewer
    find it, especially given this feature's history.]

Given the history on this issue, I'd rather get feedback early and iterate
than have this merge and need another revert — happy to adjust scope,
approach, or split this into smaller PRs if that's easier to review.

@kushmunjal1kmkm kushmunjal1kmkm requested a review from a team as a code owner July 12, 2026 19:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: dark mode

1 participant