Spec covers badge repositioning (subreddit + comment count), light/dark mode support, user-configurable colors, per-subreddit overrides, and extension popup settings UI. Co-authored-by: Cursor <cursoragent@cursor.com>
8.6 KiB
Firefox Reddit Tweaks — Design Spec
Date: 2026-08-26 Status: Approved
Overview
A Firefox extension that reskins old Reddit post listings by relocating the subreddit name and comment count into styled badge elements positioned above each post title. The original elements are hidden and replaced by clickable badge links.
Target: old.reddit.com only (including www.reddit.com when the user's preference renders old Reddit).
Scope: All pages where posts appear with subreddit and comment metadata — front page, subreddit listings, user profiles, search results, multi-reddits, and comment pages.
Architecture
Approach
Pure CSS + vanilla JS content script. No frameworks, no build step. The extension popup uses plain HTML/CSS/JS for the settings UI.
Rationale: Old Reddit has a stable, well-known DOM structure. The scope is small enough that a framework or build tooling would add unnecessary complexity. The modular file layout supports adding new tweaks later.
File Layout
firefox-reddit-tweaks/
├── manifest.json
├── content/
│ ├── main.js # Entry point, orchestrates tweaks
│ ├── tweaks/
│ │ └── badges.js # Subreddit + comment badge tweak
│ └── styles/
│ └── badges.css # Badge styling
├── popup/
│ ├── popup.html # Settings UI
│ ├── popup.js # Settings logic
│ └── popup.css # Settings styling
├── icons/
│ ├── icon-48.png
│ └── icon-96.png
└── lib/
└── settings.js # Shared settings read/write (browser.storage.sync)
Manifest
- Manifest V2 (Firefox fully supports V2).
content_scriptsmatched to*://old.reddit.com/*and*://www.reddit.com/*. Onwww.reddit.com, the script naturally handles the old-vs-new ambiguity because it targetsdiv.thingelements, which only exist when old Reddit is rendered.- Permissions:
storage(for user settings),activeTab. browser_actionfor the popup.
Modularity
Each tweak is an individual file under content/tweaks/, responsible for one self-contained modification. main.js loads settings and calls each enabled tweak. Adding a new tweak means: drop a file in tweaks/, wire it in main.js.
Badge Tweak — DOM Manipulation
Source Elements
Old Reddit renders each post as a div.thing. Relevant children:
- Subreddit name:
a.subredditinsidep.tagline - Comment count:
a.commentsinsideul.flat-list.buttons
Process
- Query all
div.thingelements on the page. - For each post, extract the subreddit link's
href/text and the comments link'shref/text (parsing the number from the text). - Create two badge elements (styled
<a>tags) and insert them into a new containerdiv.reddit-tweaks-badges, placed as the first child of the post'sdiv.entry(above the title). - Hide the original subreddit element in the tagline and the comments link in the flat-list via CSS (
display: none). - Mark each processed post with
data-rt-processedto prevent double-processing.
Badge HTML Structure
<div class="reddit-tweaks-badges">
<a class="rt-badge rt-badge--subreddit" href="/r/example/">r/example</a>
<a class="rt-badge rt-badge--comments" href="/r/example/comments/abc123/">12 comments</a>
</div>
All injected elements use an rt- prefix to avoid class name collisions with Reddit.
Dynamic Content
A MutationObserver on div#siteTable (the post container) watches for new div.thing children, covering RES infinite scroll and Reddit's own pagination. New posts are processed on insertion.
Badge Styling
Default Colors
| Property | Light Mode | Dark Mode |
|---|---|---|
| Subreddit background | transparent |
transparent |
| Subreddit border | #c84a20 |
#ff6b3d |
| Subreddit text | #c84a20 |
#ff6b3d |
| Comments background | #e0e0e0 |
#3a3a3a |
| Comments border | #4a4a4a |
#888888 |
| Comments text | #4a4a4a |
#cccccc |
Shared Badge Properties
display: inline-blockborder: 1px solid(color from settings)border-radius: 3pxpadding: 2px 6pxfont-size: 11pxfont-weight: boldtext-decoration: nonevertical-align: middlemargin-right: 6px- Hover: slight opacity reduction to signal clickability
- Container (
div.reddit-tweaks-badges):margin-bottom: 4px
Dark Mode Detection
The content script checks for RES night mode via the .res-nightmode class on <body> and applies the dark palette via a CSS class toggle (rt-dark). Users can also force a mode in settings (Auto / Light / Dark).
CSS Custom Properties
Colors are applied via CSS custom properties (--rt-sub-bg, --rt-sub-border, --rt-sub-text, --rt-com-bg, --rt-com-border, --rt-com-text) set on the badge container. The stylesheet references them with fallbacks to light mode defaults.
For per-subreddit overrides, inline styles are set on individual badges when a matching entry exists in the settings.
Settings
Storage
All settings stored in browser.storage.sync for cross-device sync.
Configurable Properties
| Setting Key | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | true |
Master toggle |
darkMode |
string | "auto" |
"auto" / "light" / "dark" |
light.subredditBgColor |
string | transparent |
Light mode subreddit badge background |
light.subredditBorderColor |
string | #c84a20 |
Light mode subreddit badge border |
light.subredditTextColor |
string | #c84a20 |
Light mode subreddit badge text |
light.commentsBgColor |
string | #e0e0e0 |
Light mode comments badge background |
light.commentsBorderColor |
string | #4a4a4a |
Light mode comments badge border |
light.commentsTextColor |
string | #4a4a4a |
Light mode comments badge text |
dark.subredditBgColor |
string | transparent |
Dark mode subreddit badge background |
dark.subredditBorderColor |
string | #ff6b3d |
Dark mode subreddit badge border |
dark.subredditTextColor |
string | #ff6b3d |
Dark mode subreddit badge text |
dark.commentsBgColor |
string | #3a3a3a |
Dark mode comments badge background |
dark.commentsBorderColor |
string | #888888 |
Dark mode comments badge border |
dark.commentsTextColor |
string | #cccccc |
Dark mode comments badge text |
subredditColors |
object | {} |
Map of subreddit name → {bg, border, text} |
Live Updates
The content script listens for browser.storage.onChanged to apply settings changes without requiring a page reload.
Settings UI (Popup)
- Master toggle — enable/disable the extension.
- Badge Colors section with Light Mode and Dark Mode sub-sections, each showing:
- Subreddit badge: background, border, text color pickers
- Comments badge: background, border, text color pickers
- "Reset to defaults" button per mode
- Dark mode detection dropdown: Auto (detect RES) / Force Light / Force Dark.
- Per-subreddit overrides — add/remove list. Each entry: subreddit name text input + three color pickers for the subreddit badge.
- Reset all settings button at the bottom.
Settings save immediately on change. Clean, minimal styling following Firefox extension popup conventions.
Error Handling & Edge Cases
- Missing elements: If a post lacks a subreddit link (e.g., on a subreddit page where it's implicit) or comments link, that badge is skipped. No errors thrown.
- Already processed:
data-rt-processedattribute prevents double-processing. - RES infinite scroll: MutationObserver catches dynamically added posts.
- Subreddit pages: Subreddit badge is skipped when the subreddit name isn't present in the post tagline (it's implied by the page context).
- Comment pages: The main post at the top is a
div.thingand gets badges. Comment entries lack subreddit/comment-count structure and are naturally skipped. - Extension disabled: When
enabledisfalse, the content script does nothing and any previously injected badges/styles are removed.
Testing Strategy
Manual testing via about:debugging (temporary add-on). No automated test framework for v1.
Test Checklist
- Badges appear on front page posts
- Badges appear on subreddit listing pages (subreddit badge omitted when redundant)
- Badges appear on user profile pages
- Badges are clickable links to correct destinations
- Original subreddit/comment elements are hidden
- RES infinite scroll loads get badged
- Dark mode detection works with RES night mode
- Settings changes apply live without page reload
- Per-subreddit color overrides work
- Reset to defaults works