| name | dark-mode |
| description | Web and App implementation guide for Dark Mode Design. Trigger when user wants dark surfaces, reduced eye strain, and premium sleek aesthetics. |
| date_added | 2026-06-17 |
| risk | safe |
| source | self |
| source_type | self |
Dark Mode Design
"Not just inverted colors. A carefully constructed hierarchy of light on dark."
When to Use
Use this sub-style when the user's request matches the aesthetic described above. This is a child reference of the design-it skill and is not meant to be triggered directly.
Core Principles
- Never Pure Black: True
#000000 causes smearing on OLED screens and extreme eye strain with white text. Use dark greys (e.g., #121212 or #0A0A0A).
- Elevation via Lightness: In light mode, shadows show elevation. In dark mode, shadows are invisible, so elevated surfaces must be lighter than the background.
- Desaturated Accents: Saturated colors vibrate painfully against dark backgrounds. Tone down the saturation of brand colors.
Visual DNA
- Colors: Midnight Luxury or Minimalist Slate (inverted). Background
#121212. Elevated cards #1E1E1E, #252525. Primary text #E1E1E1 (not #FFFFFF).
- Typography: Standard highly readable sans-serifs, but often dropped down one font weight compared to light mode, as light text on dark backgrounds appears optically thicker.
- Shadows: Pure black shadows, but with much lower opacity, mostly to separate slightly different shades of grey.
Web Implementation
:root {
--bg-base: #121212;
--bg-elevated-1: #1E1E1E;
--bg-elevated-2: #242424;
--text-high-emphasis: rgba(255, 255, 255, 0.87);
--text-medium-emphasis: rgba(255, 255, 255, 0.60);
--accent-color: #BB86FC;
}
body {
background-color: var(--bg-base);
color: var(--text-high-emphasis);
font-weight: 300;
}
.dark-card {
background-color: var(--bg-elevated-1);
border-radius: 8px;
padding: 24px;
border: 1px solid rgba(255, 255, 255, 0.05);
}
.dark-card:hover {
background-color: (--bg-elevated-);
}
{
: (--accent-color);
: ;
: ;
: none;
: ;
: ;
}
App Implementation
SwiftUI
struct DarkModeView: View {
@Enprojectnment(\.colorScheme) var colorScheme
var body: some View {
ScrollView {
VStack(spacing: 20) {
VStack(alignment: .leading, spacing: 12) {
Text("Elevation via Lightness")
.font(.headline)
.foregroundColor(.primary)
Text("In dark mode, elevated surfaces are lighter grey, not shadowed.")
.font(.subheadline)
.foregroundColor(.secondary)
}
.padding()
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color(UIColor.secondarySystemBackground))
.cornerRadius(12)
Button(action: {}) {
Text("Desaturated Accent")
.fontWeight(.semibold)
.foregroundColor(.black)
.padding()
.frame(maxWidth: .infinity)
.background(Color(red: 0.73, green: 0.52, blue: 0.98))
.cornerRadius()
}
}
.padding()
}
.background((.systemBackground))
}
}
- Rely on Semantics: SwiftUI's
Color.primary, Color.secondary, Color(UIColor.systemBackground) and Color(UIColor.secondarySystemBackground) handle perfect dark mode transitions automatically.
- Avoid forcing explicit hex codes for backgrounds unless you are building a custom-themed app.
Flutter
import 'package:flutter/material.dart';
class DarkModeApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
// Configure the Dark Theme
themeMode: ThemeMode.dark,
darkTheme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: const Color(0xFF121212), // Standard dark background
cardColor: const Color(0xFF1E1E1E), // Elevated surface
colorScheme: const ColorScheme.dark().copyWith(
primary: const Color(0xFFBB86FC), // Desaturated accent
onPrimary: Colors.black, // Dark text on light accent
surface: const Color(0xFF1E1E1E),
),
),
home: Scaffold(
appBar: AppBar(title: const Text('Dark Mode', style: TextStyle(color: Colors.white70))),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
Card(
elevation: 0, // Shadows don't show well anyway
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: BorderSide(color: Colors.white.withOpacity(0.05)), // Subtle border
),
child: const Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Elevation via Lightness', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 8),
Text('Elevated surfaces use lighter greys.', style: TextStyle(color: Colors.white60)),
],
),
),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {},
child: const Text('Desaturated Accent'),
),
],
),
),
);
}
}
- When using
ThemeData.dark(), actively override scaffoldBackgroundColor to #121212 and cardColor to #1E1E1E.
- Ensure your
colorScheme.onPrimary is black so text is readable when placed on top of your desaturated primary accent button.
React Native
import { useColorScheme } from 'react-native';
const DarkModeScreen = () => {
const isDark = useColorScheme() === 'dark';
const theme = {
bgBase: isDark ? '#121212' : '#FFFFFF',
bgElevated: isDark ? '#1E1E1E' : '#F5F5F5',
textHigh: isDark ? 'rgba(255, 255, 255, 0.87)' : 'rgba(0, 0, 0, 0.87)',
textMedium: isDark ? 'rgba(255, 255, 255, 0.60)' : 'rgba(0, 0, 0, 0.60)',
accent: isDark ? '#BB86FC' : '#6200EE',
onAccent: isDark ? '#000' : '#FFF',
};
return (
<View style={{ flex: 1, backgroundColor: theme.bgBase, padding: 16 }}>
<View style={{
backgroundColor: theme.bgElevated,
padding: 24,
borderRadius: 12,
borderWidth: ? ,
'(,,,)',
}}>
Elevation via Lightness
Elevated surfaces use lighter greys.
Desaturated Accent
);
};
- Rely on
useColorScheme() hook from React Native.
- Define a strict dictionary of your color tokens. Notice how
theme.accent shifts from a vibrant purple (#6200EE) in light mode to a desaturated pastel purple (#BB86FC) in dark mode.
Jetpack Compose
@Composable
fun DarkModeScreen() {
val darkColors = darkColorScheme(
background = Color(0xFF121212),
surface = Color(0xFF1E1E1E),
primary = Color(0xFFBB86FC),
onPrimary = Color.Black,
onBackground = Color.White.copy(alpha = 0.87f),
onSurface = Color.White.copy(alpha = 0.87f)
)
MaterialTheme(colorScheme = darkColors) {
Column(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.padding(16.dp)
) {
Card(
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface),
shape = RoundedCornerShape(12.dp),
border = BorderStroke(1.dp, Color.White.copy(alpha = 0.05f))
) {
Column(modifier = Modifier.padding(24.dp)) {
Text("Elevation via Lightness",
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onSurface)
Spacer(Modifier.height(8.dp))
Text("Elevated surfaces use lighter greys.",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f))
}
}
Spacer(Modifier.height(20.dp))
Button(
onClick = {},
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.primary,
contentColor = MaterialTheme.colorScheme.onPrimary
),
modifier = Modifier.fillMaxWidth().height(50.dp)
) {
Text("Desaturated Accent", fontWeight = FontWeight.Bold)
}
}
}
}
- Material 3 handles Dark Mode semantics perfectly. Define your
darkColorScheme.
- Use
Color(0xFF1E1E1E) for surface and Color(0xFF121212) for background. Compose will automatically map these to Cards and Scaffolds.
Do's and Don'ts
- DO: Meet WCAG contrast standards. Just because it's dark doesn't mean the text should be illegibly dim.
- DON'T: Use bright, highly saturated primary colors.
Limitations
- This is a styling reference and does not replace enprojectnment-specific validation, accessibility testing, or expert review.
- Ensure appropriate contrast ratios and responsive behaviors are verified separately.