PHPackages                             ernestdefoe/theme-toggle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. ernestdefoe/theme-toggle

ActiveFlarum-extension[Utility &amp; Helpers](/categories/utility)

ernestdefoe/theme-toggle
========================

Adds a day/night/system toggle button to the Flarum 2 header. Works with any theme via the native data-theme attribute.

3.0.6(2w ago)0105↑242.9%MITTypeScriptPHP ^8.3CI passing

Since May 20Pushed 2w agoCompare

[ Source](https://github.com/ernestdefoe/theme-toggle)[ Packagist](https://packagist.org/packages/ernestdefoe/theme-toggle)[ Docs](https://github.com/ernestdefoe/theme-toggle)[ RSS](/packages/ernestdefoe-theme-toggle/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (9)Dependencies (1)Versions (12)Used By (0)

Theme Toggle
============

[](#theme-toggle)

[![Floxum](https://camo.githubusercontent.com/dcacee3a6cde61b0f7fe8f59ace60b768bbe5e72499ff0f80fe760e879f60464/68747470733a2f2f666c6f78756d2e636f6d2f657874656e73696f6e2f65726e6573746465666f652f7468656d652d746f67676c652f62616467652f6e616d65)](https://floxum.com/extension/ernestdefoe/theme-toggle)[![Version](https://camo.githubusercontent.com/88e7e11ec4b3284fcc23f3be674f4983387cbfec9890b1d9a56c45de94fe3b62/68747470733a2f2f666c6f78756d2e636f6d2f657874656e73696f6e2f65726e6573746465666f652f7468656d652d746f67676c652f62616467652f686967686573742d76657273696f6e)](https://floxum.com/extension/ernestdefoe/theme-toggle)[![Downloads](https://camo.githubusercontent.com/c90061ebb7eecafba163ffb78aab5902413b07ed37c7d8b0ebff81cc26a28e07/68747470733a2f2f666c6f78756d2e636f6d2f657874656e73696f6e2f65726e6573746465666f652f7468656d652d746f67676c652f62616467652f646f776e6c6f616473)](https://floxum.com/extension/ernestdefoe/theme-toggle)[![Review](https://camo.githubusercontent.com/145cfe44cb5279a960113463e175fa586f4f1c19cfb92ec292ccf78902d91f0c/68747470733a2f2f666c6f78756d2e636f6d2f657874656e73696f6e2f65726e6573746465666f652f7468656d652d746f67676c652f62616467652f726576696577)](https://floxum.com/extension/ernestdefoe/theme-toggle)[![License](https://camo.githubusercontent.com/5656d2a133e537bb938a7c2c92faf89510f74a89f59610c3745afc2e61f6c187/68747470733a2f2f666c6f78756d2e636f6d2f657874656e73696f6e2f65726e6573746465666f652f7468656d652d746f67676c652f62616467652f6c6963656e7365)](https://floxum.com/extension/ernestdefoe/theme-toggle)

A small, theme-agnostic day/night/system picker for the Flarum 2 header. Drops into any Flarum 2 theme that respects the native `` signal (every theme that ships with or extends Flarum 2 does, including the default).

[![License](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)[![Flarum](https://camo.githubusercontent.com/685486b52fcf58814852c830ccf7d3873e94c32a77ef67b19bbe1958651d2fe9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466c6172756d2d253545322e302d6f72616e67652e737667)](https://camo.githubusercontent.com/685486b52fcf58814852c830ccf7d3873e94c32a77ef67b19bbe1958651d2fe9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466c6172756d2d253545322e302d6f72616e67652e737667)[![PHP](https://camo.githubusercontent.com/3ed0aba78d953e7a0393ff62845b98b4401a24d21135a2f872023ae25ce19fb3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d253545382e332d3737376262342e737667)](https://camo.githubusercontent.com/3ed0aba78d953e7a0393ff62845b98b4401a24d21135a2f872023ae25ce19fb3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d253545382e332d3737376262342e737667)[![TypeScript](https://camo.githubusercontent.com/618e15a15f5028b2d5a711ab8af8b24f6f8fbd7977d3f990a941d760a1855acd/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f547970655363726970742d7374726963742d3331373863362e737667)](https://camo.githubusercontent.com/618e15a15f5028b2d5a711ab8af8b24f6f8fbd7977d3f990a941d760a1855acd/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f547970655363726970742d7374726963742d3331373863362e737667)

Screenshots
-----------

[](#screenshots)

### Desktop — header button

[](#desktop--header-button)

A compact icon button next to Search / Sign Up / Log In. The icon reflects the active choice (☾ dark, ☀ light, ◐ system).

[![Desktop header](screenshots/desktop-header.png)](screenshots/desktop-header.png)

### Desktop — dropdown open

[](#desktop--dropdown-open)

Five choices, each with a matching icon. The active choice is marked with a checkmark.

[![Desktop dropdown](screenshots/desktop-dropdown.png)](screenshots/desktop-dropdown.png)

### Mobile — slide-out drawer

[](#mobile--slide-out-drawer)

On phone-width viewports Flarum re-renders `HeaderSecondary` inside `.App-drawer`. The button switches to a labeled, full-width menu row so it lines up with Search / Sign Up / Log In.

[![Mobile drawer](screenshots/mobile-drawer.png)](screenshots/mobile-drawer.png)

Features
--------

[](#features)

- **Five choices.** Dark, Dark (high contrast), Light, Light (high contrast), System.
- **Native Flarum 2 signal.** The extension only flips `` and `localStorage` — no theme-specific CSS, so it composes with any well-behaved Flarum 2 theme (default, [Aurora](https://github.com/ernestdefoe/aurora), or any third-party theme).
- **System mode honours OS preferences.** When System is active, the theme follows `prefers-color-scheme` for light/dark and `prefers-contrast: more` for the `-hc` variants — so an accessibility user with macOS / Windows "Increase contrast" turned on automatically gets the right palette.
- **Live OS updates.** Changes to the OS theme or contrast preference are picked up immediately while the tab is open, with no reload.
- **Persists per visitor.** Your choice is stored in `localStorage` under `ernestdefoe-theme-toggle.choice` and re-applied on every page load before paint, so there's no FOUC.
- **Respects the admin default.** Until a visitor explicitly picks a choice, Flarum's **Admin → Appearance → Color Scheme** setting is left untouched.
- **Mobile-aware UI.** Renders as a compact icon button in the desktop header and as a labeled `"◐ Theme"` row inside the mobile slide-out drawer (where icon-only buttons would float disconnected from the surrounding Sign Up / Log In rows).
- **Localized.** All visible strings come from `locale/en.yml` and can be overridden in your forum's locale files.
- **TypeScript end-to-end.** Sources are authored in TypeScript and type-checked against Flarum core's bundled `.d.ts` files. `npm run check-typings` runs `tsc --noEmit`.

Compatibility
-------------

[](#compatibility)

- Flarum core `^2.0`
- PHP `^8.3`
- Pairs with any theme. Tested with the default theme and the Aurora theme.

Install
-------

[](#install)

```
composer require ernestdefoe/theme-toggle
php flarum cache:clear
```

Then enable **Theme Toggle** from the admin panel's Extensions page.

Development
-----------

[](#development)

```
cd js
npm install
npm run build           # production bundle (writes js/dist/forum.js)
npm run dev             # watch mode for development
npm run check-typings   # tsc --noEmit, requires `composer install` at repo root first
```

The TypeScript path mapping in `js/tsconfig.json` points at `../vendor/flarum/core/js/dist-typings/`, so `composer install` at the repo root must run before `check-typings` can resolve `flarum/*` imports.

### Project layout

[](#project-layout)

```
extend.php                                Flarum extension bootstrap
composer.json                             Package manifest
locale/en.yml                             User-facing strings
less/forum.less                           Header + drawer styling
js/
  forum.ts                                Webpack entry point
  tsconfig.json                           Extends flarum-tsconfig
  src/forum/
    index.ts                              Initializer + HeaderSecondary hook
    theme.ts                              Choice/storage helpers + media listener
    components/ThemeToggle.tsx            The Dropdown component
  dist/forum.js                           Compiled bundle (committed)
screenshots/                              Images in this README

```

How it works
------------

[](#how-it-works)

Flarum 2 ships four `data-theme` values: `light`, `light-hc`, `dark`, and `dark-hc`. Themes are expected to define their dark tokens as the default and their light tokens under `[data-theme^='light']`, with a high-contrast layer under `[data-theme^='light-hc']` / `[data-theme^='dark-hc']`. Because those selectors use `^=` (prefix match), setting `data-theme="light-hc"` activates *both* the regular light palette and its HC overrides via the cascade.

This extension just sets that attribute client-side:

- On boot, `theme.ts` reads the saved choice from `localStorage` and writes the corresponding string to `` **before** the initializer runs, so the page never paints in the wrong palette.
- The `ThemeToggle` component reads the same choice for its icon and dropdown state.
- When the user picks a new option, the choice is written to `localStorage`, `` is updated, and Mithril redraws the button.
- In System mode, a `matchMedia` listener for `prefers-color-scheme` and `prefers-contrast: more` re-applies the choice live.

No theme-specific CSS, no setting payload, no server round-trip.

Translations
------------

[](#translations)

Override any string by adding the matching key under `ernestdefoe-theme-toggle.forum.toggle.*` in your forum's locale file:

KeyDefault`label``Theme``option_dark``Dark``option_dark_hc``Dark (high contrast)``option_light``Light``option_light_hc``Light (high contrast)``option_system``System`License
-------

[](#license)

[MIT](LICENSE) © Ernest Defoe

###  Health Score

46

—

FairBetter than 92% of packages

Maintenance97

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity55

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 87.5% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

9

Last Release

15d ago

Major Versions

2.0.1 → 3.0.02026-05-21

### Community

Maintainers

![](https://www.gravatar.com/avatar/c9978664264055711c21fbcf73c937f758df771d9cb40f6a25370b10123e7abc?d=identicon)[ernestdefoe](/maintainers/ernestdefoe)

---

Top Contributors

[![ernestdefoe](https://avatars.githubusercontent.com/u/24905286?v=4)](https://github.com/ernestdefoe "ernestdefoe (14 commits)")[![claude](https://avatars.githubusercontent.com/u/81847?v=4)](https://github.com/claude "claude (2 commits)")

---

Tags

themetoggleflarumdark-modelight-modeflarum-extension

### Embed Badge

![Health badge](/badges/ernestdefoe-theme-toggle/health.svg)

```
[![Health](https://phpackages.com/badges/ernestdefoe-theme-toggle/health.svg)](https://phpackages.com/packages/ernestdefoe-theme-toggle)
```

###  Alternatives

[flarum-lang/russian

Russian language pack for Flarum.

12127.5k](/packages/flarum-lang-russian)[fof/byobu

Well integrated, advanced private discussions.

61112.4k10](/packages/fof-byobu)[datlechin/flarum-link-preview

Automatically display a rich preview of the link contents.

1717.1k](/packages/datlechin-flarum-link-preview)[fof/discussion-language

Specify the language a discussion is written in &amp; sort by language

1032.0k](/packages/fof-discussion-language)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
