Skip to content

feat: replace native theme select with floating dropdown UI#32148

Open
owaiss0 wants to merge 11 commits into
cloudflare:productionfrom
owaiss0:feat/theme-dropdown-ui
Open

feat: replace native theme select with floating dropdown UI#32148
owaiss0 wants to merge 11 commits into
cloudflare:productionfrom
owaiss0:feat/theme-dropdown-ui

Conversation

@owaiss0

@owaiss0 owaiss0 commented Jul 18, 2026

Copy link
Copy Markdown

PR: Implement Cloudflare-styled Floating Theme Dropdown

📝 Summary

Replaced the browser-native <select> element for theme switching with a custom floating popover dropdown that matches the existing Cloudflare header dropdown pattern (same design as the "Help" dropdown in HeaderDropdowns.tsx).

This implementation is built as a pure Astro & vanilla JS Custom Element (starlight-theme-select) inside ThemeSelect.astro. It executes a tiny inline script immediately as the HTML parses to read localStorage and apply the correct active icon and text before the browser paints the screen, providing a 0ms flicker-free (FOUC-free) load experience.


🔍 Before vs After

1. Desktop Theme Selector

Feature Before (Default Starlight) After (Cloudflare Custom)
UI Control Browser-native <select> dropdown. Custom floating popover menu with checkmark selection indicators.
Caret Icon Thin Starlight chevron caret. Bold PiCaretDownBold caret matching the size and weight of other header dropdowns.
Spacing & Alignment Loose, generic browser select padding. Absolute layout alignment matching Cloudflare's exact offsets, ensuring zero overlap between the left icon and the text.
Hover Transitions Basic browser color overrides. Smooth opacity and color transition: both the text and caret inherit the hover state and change color together.

2. Mobile Theme Selector

Feature Before (Default Starlight) After (Cloudflare Custom)
Footer Integration Standard native dropdown inside mobile sidebar footer. Custom floating menu popover styled consistently with the rest of the application.
Mobile UX Options menu could bleed or overlap sidebar elements. Popover menu uses flip() positioning to open upward in the footer, and automatically closes on page scroll.

🛠️ Technical Details

  • FOUC-Free Rendering: Moving the implementation away from React to a vanilla JS Custom Element allows us to run an inline parsing script. This prevents the typical "Auto" text flash on page reload before hydration.
  • Accessibility (a11y): Trigger button has explicit aria-haspopup="listbox", aria-expanded state tracking, and option buttons have role="option" with aria-selected tracking for screen reader support.
  • Storage Safety: All localStorage read and write operations are wrapped in try/catch block guards to ensure the UI does not crash in Safari Private Mode or other restricted environments.
  • Astro Config Override: The override is registered in astro.config.ts under components.ThemeSelect, automatically styling the theme selector in both the desktop header and the mobile menu footer.

Replace the browser-native <select> element for theme switching with a
custom floating dropdown that matches the existing Cloudflare header
dropdown pattern (HeaderDropdowns.tsx).

Changes:
- New ThemeDropdown.tsx React component using @floating-ui/react
- New ThemeSelect.astro override wrapping ThemeDropdown
- Registered ThemeSelect override in astro.config.ts
- Removed obsolete starlight-theme-select CSS overrides from Header.astro

The dropdown uses the exact same Starlight SVG icons (sun, moon, laptop,
down-caret) with identical sizing and absolute positioning to match the
original layout pixel-for-pixel. Includes flip() middleware for mobile
footer positioning and scroll-to-close for sidebar compatibility.
@owaiss0
owaiss0 requested review from a team and kodster28 as code owners July 18, 2026 02:45
@cloudflare-docs-bot

cloudflare-docs-bot Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Review

✅ No issues found in commit 90e3ed6.

Code Review

This code review is in beta and may not always be helpful — use your judgment.

No code review issues found.

Conventions

No convention issues found.

Style Guide Review

No style-guide issues found.

Commands

Only codeowners can run commands. Post a comment with the command to trigger it.

Command Description
/review Runs a review now. Incremental if a prior review exists, full if not.
/full-review Re-reviews the entire PR diff from scratch, ignoring incremental history. Useful after a rebase, when you want a fresh review, or if the bot gets out of sync and reports issues that no longer exist.
/ignore-review-limit Permanently lifts the 2-review automatic limit for this PR. Future pushes will trigger reviews as normal.
/disable-auto-review Stops automatic reviews from triggering on future pushes to this PR. Codeowners can still run /review or /full-review manually.
/rebase Rebases the PR branch against production. Stops if there are conflicts and reports which files conflict.
/rebaseWithConflicts Rebases against production and attempts to resolve conflicts automatically using AI. Stops with an explanation if confidence is not high enough.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants