Implementing Dark Mode in Your SaaS - Complete Technical Guide
Learn how to add and customize dark mode support in your Astro application. This comprehensive guide covers implementation, best practices, accessibility, and user experience considerations.
Dark mode has become an essential feature for modern web applications. This comprehensive guide shows you how SaaSKit implements dark mode and how you can customize it for your needs.
Why Dark Mode Matters
Dark mode isn’t just a trend—it’s a user expectation. Here’s why it’s important:
User Benefits
- Reduced eye strain in low-light conditions
- Battery savings on OLED displays (up to 30% on some devices)
- Better focus for many users
- Accessibility for users with light sensitivity
- Modern aesthetic that users prefer
Business Benefits
- Increased user satisfaction and retention
- Competitive advantage (many users expect it)
- Better accessibility compliance
- Professional appearance
Implementation Overview
SaaSKit uses a class-based dark mode approach with Tailwind CSS. This provides:
- Performance: No JavaScript required for styling
- Flexibility: Easy to customize
- Compatibility: Works with all modern browsers
- Accessibility: Respects system preferences
Technical Implementation
Let’s dive into how dark mode is implemented in SaaSKit.
Configuration
Dark mode is configured in tailwind.config.mjs:
export default {
darkMode: 'class',
// ... rest of config
}
The 'class' strategy means Tailwind will apply dark mode styles when the dark class is present on the HTML element.
Toggle Component
The DarkModeToggle component handles theme switching:
// Simplified version
const toggleDarkMode = () => {
const isDark = document.documentElement.classList.toggle('dark');
localStorage.setItem('theme', isDark ? 'dark' : 'light');
};
Key features:
- Toggles the
darkclass on<html> - Persists preference in localStorage
- Provides visual feedback
- Accessible with proper ARIA labels
Initialization
On page load, the theme is initialized:
if (localStorage.theme === 'dark' ||
(!('theme' in localStorage) &&
window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark');
}
This ensures:
- User preference is respected
- System preference is used as fallback
- No flash of wrong theme (FOUC)
Color Considerations
Choosing the right colors for dark mode is crucial.
Contrast Ratios
Maintain WCAG AA standards:
- Normal text: 4.5:1 contrast ratio minimum
- Large text: 3:1 contrast ratio minimum
- Interactive elements: Clear visual distinction
Color Palette
SaaSKit uses a carefully chosen palette:
/* Light mode */
--accent-dark: #343434;
--accent-teal: #055e68;
--accent-green: #62a388;
--accent-light: #b9d2d2;
/* Dark mode adjustments */
/* Colors are adjusted for better visibility */
Best practices:
- Don’t just invert colors
- Adjust saturation and brightness
- Test readability in both themes
- Consider color-blind users
Background Colors
Choose backgrounds that:
- Reduce eye strain (not pure black)
- Maintain sufficient contrast
- Feel comfortable for extended reading
- Work with your brand colors
Recommended:
- Light mode:
#ffffffor#f9fafb - Dark mode:
#1a1a1aor#0f172a(not#000000)
Component Styling
Here’s how to style components for both themes.
Using Tailwind Classes
<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
Content that adapts to theme
</div>
Conditional Styling
For complex components:
const className = clsx(
'base-styles',
isDark ? 'dark-styles' : 'light-styles'
);
CSS Variables
For dynamic theming:
:root {
--bg-primary: #ffffff;
--text-primary: #1a1a1a;
}
.dark {
--bg-primary: #1a1a1a;
--text-primary: #ffffff;
}
Accessibility
Dark mode should be accessible to all users.
System Preference Detection
Respect user’s OS preference:
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
prefersDark.addEventListener('change', (e) => {
// Update theme if no manual preference set
});
Keyboard Navigation
Ensure toggle is keyboard accessible:
- Focusable with Tab
- Activatable with Enter/Space
- Clear focus indicators
Screen Readers
Provide proper labels:
<button aria-label="Toggle dark mode">
<MoonIcon />
</button>
User Experience
Great dark mode UX goes beyond just switching colors.
Smooth Transitions
Add transitions for theme changes:
* {
transition: background-color 0.3s, color 0.3s;
}
Note: Be careful with transitions on all elements—it can cause performance issues. Target specific properties instead.
Persistence
Save user preference:
- localStorage: Persists across sessions
- Cookies: Works across subdomains
- Server-side: For logged-in users
Default Behavior
When no preference is set:
- Check localStorage first
- Fall back to system preference
- Default to light mode if neither available
Testing Dark Mode
Thoroughly test your dark mode implementation.
Visual Testing
- Check all components in both themes
- Test on different screen sizes
- Verify contrast ratios
- Check for color bleeding
Functional Testing
- Toggle works correctly
- Preference persists
- No flash of wrong theme
- System preference detection works
Accessibility Testing
- Screen reader compatibility
- Keyboard navigation
- Color contrast validation
- Focus indicators visible
Common Issues and Solutions
Flash of Unstyled Content (FOUC)
Problem: Wrong theme flashes before JavaScript loads
Solution: Initialize theme in <head> before body renders
Inconsistent Colors
Problem: Some elements don’t adapt to dark mode
Solution: Use Tailwind’s dark: prefix consistently
Performance
Problem: Transitions cause jank
Solution: Use transform and opacity for animations, avoid layout properties
Images
Problem: Images look wrong in dark mode
Solution: Use CSS filters or provide dark mode variants
Best Practices Summary
- Respect user choice: Always honor manual selection
- System preference: Use as intelligent default
- Smooth transitions: Make theme changes feel natural
- Accessibility first: Ensure contrast and readability
- Test thoroughly: Check all components and states
- Performance: Don’t sacrifice speed for transitions
- Consistency: Apply dark mode across entire application
Advanced Techniques
Theme Variants
Support multiple themes:
const themes = ['light', 'dark', 'auto'];
Custom Theme Colors
Allow users to customize:
const customTheme = {
primary: userSelectedColor,
background: userSelectedBg,
};
Scheduled Themes
Auto-switch based on time:
const hour = new Date().getHours();
if (hour >= 18 || hour < 6) {
enableDarkMode();
}
Conclusion
Dark mode is more than a feature—it’s a user expectation. By implementing it thoughtfully:
- You improve user experience
- Increase accessibility
- Show attention to detail
- Stay competitive
Remember: Great dark mode is invisible. Users shouldn’t notice the implementation—they should just enjoy using your application in their preferred theme.
Start with the basics, test thoroughly, and iterate based on user feedback. Your users will appreciate the effort!
Related Posts
Best Practices for SaaS Landing Pages - Conversion Optimization Guide
Discover proven strategies to create high-converting SaaS landing pages. Learn about design principles, copywriting, user experience, and conversion optimization techniques.
Getting Started with SaaSKit - Complete Setup Guide
Learn how to quickly set up and customize your SaaS landing page template. This comprehensive guide covers installation, configuration, customization, and deployment.