Files
pos-system/microservices/.agent/skills/blazor-theme-patterns/SKILL.md
Ho Ngoc Hai 76d75c753b Migrate
2026-05-23 18:37:02 +07:00

138 lines
4.6 KiB
Markdown

---
name: blazor-theme-patterns
description: Best practices for implementing Light/Dark themes in Blazor (MudBlazor) applications, ensuring synchronization between C# and CSS.
---
# Blazor Theme Patterns
This skill documents the patterns and best practices for implementing robust Light/Dark theming in Blazor applications, specifically when using **MudBlazor** alongside **Custom CSS**.
## 1. The Hybrid Theming Problem
Blazor apps often have two sources of truth for styling:
1. **MudBlazor Theme (`MudTheme` in C#)**: Controls MudBlazor components (AppBar, Drawer, Buttons).
2. **CSS Variables (`app.css`)**: Controls native HTML elements (`body`, `h1`, custom divs) and global layout.
**Risk**: If these two are not synchronized, you get "partial themes" (e.g., Dark Header but Light Body).
## 2. Solution: synchronization Pattern
Always synchronize the Blazor theme state with the DOM via JavaScript Interop.
### Step 1: Define CSS Variables with Data Attribute
In your `app.css`, define variables using the `[data-theme="dark"]` selector.
```css
:root {
/* Light Mode Defaults */
--bg-primary: #ffffff;
--text-primary: #18181b;
}
[data-theme="dark"], :root[data-theme="dark"] {
/* Dark Mode Overrides */
--bg-primary: #09090b;
--text-primary: #fafafa;
}
/* Enforce Body Background */
body {
background-color: var(--bg-primary) !important;
color: var(--text-primary) !important;
transition: background-color 0.3s ease;
}
```
### Step 2: Add JS Helper
In `index.html` (before `MudBlazor.min.js`), add a lightweight helper to switch attributes.
```html
<script>
window.setTheme = (theme) => {
document.documentElement.setAttribute('data-theme', theme);
}
</script>
```
### Step 3: call from Blazor Layout
In `MainLayout.razor`, inject `IJSRuntime` and call the helper when toggling the theme.
```razor
@inject IJSRuntime JSRuntime
<MudThemeProvider @bind-IsDarkMode="_isDarkMode" Theme="_theme" />
@code {
private bool _isDarkMode;
private MudTheme _theme = new();
private async Task ToggleDarkMode()
{
_isDarkMode = !_isDarkMode;
// Sync with CSS
await JSRuntime.InvokeVoidAsync("setTheme", _isDarkMode ? "dark" : "light");
}
}
```
## 3. Common Pitfalls & Solutions
### A. "Invisible" Text in Dark Mode (White on White)
**Issue**: MudBlazor's `Primary` color might be White in Dark Mode (e.g., `#fafafa`). If the `PrimaryContrastText` is not set, it might default to White, making text invisible on a Primary Filled Button.
**Fix**: Explicitly set `PrimaryContrastText` in your `PaletteDark`.
```csharp
PaletteDark = new PaletteDark()
{
Primary = "#fafafa",
PrimaryContrastText = "#18181b", // Force Black text on White Primary button
// ...
}
```
**CSS Hardening**:
If C# palette fails, force it locally in CSS:
```css
[data-theme="dark"] .mud-button-filled-primary {
color: #18181b !important;
}
```
### B. AppBar Color Mismatch
**Issue**: `MudAppBar` defaults to `Color.Primary` (often black/dark). In Light Mode, if you want a white AppBar, `Color.Primary` might conflict.
**Fix**: Use `Color="Color.Default"` and let the Theme Palette handle the background color (`AppbarBackground`).
```razor
<MudAppBar Color="Color.Default" Elevation="0" ... />
```
### C. Development Workflow (Hot Reload)
**Recommendation**: Use `dotnet watch` during development to instantly see CSS and Razor changes without restarting.
```bash
dotnet watch --project src/WebClientBase.Client
```
**Note**:
* **CSS Changes**: Applied instantly.
* **Razor Markup**: Applied instantly.
* **C# Logic (`@code`)**: usually applied instantly, but complex logic changes (like modifying `OnInitialized`) may require a manual restart (Ctrl+R).
* **Full Rebuild**: Required if you add constant fields or change method signatures that Hot Reload cannot handle.
## 4. Verification Checklist
When implementing themes, verify these points using the Browser Tool across multiple devices:
### A. Core Theme Checks
1. **Body Background**: Does it change hex codes when toggled?
2. **Primary Button Text**: Is it readable (Contrast Ratio) in *both* Light and Dark modes?
3. **Headings**: Do standard `h1`-`h6` tags invert color correctly?
### B. Responsive Checks (Crucial)
1. **Desktop (> 960px)**: Check standard navigation bar and layout.
2. **Tablet (768px - 960px)**: Check if layout adapts (e.g. grid changes).
3. **Mobile (< 768px)**:
- **Hamburger Menu**: Is the icon visible in both themes?
- **Drawer/Sidebar**: Does the drawer background match the theme (especially in Dark Mode)?
- **Mobile Navigation**: are links readable?