A beautiful, animated React dark mode toggle component with zero dependencies. Features smooth animations and customizable styling.
A smooth, animated toggle between light and dark modes
- π¨ Beautiful animations - Smooth transitions with elastic easing
- π― Zero dependencies - Only requires React and ReactDOM
- π§ Highly customizable - Colors, sizes, and behavior
- π± Responsive - Works on all screen sizes
- βΏ Accessible - Proper ARIA labels and keyboard support
- π Shadow DOM - Isolated styles that won't conflict with your app
- πΎ LocalStorage - Automatically persists theme preference
- β‘ TypeScript - Full TypeScript support with proper types
- π¦ Tiny footprint - Ships at 4.59 KB (1.79 KB gzipped)
npm install @gozenc/react-dark-mode-toggleyarn add @gozenc/react-dark-mode-toggleimport { DarkModeToggle } from "@gozenc/react-dark-mode-toggle";
function App() {
return (
<div>
<h1>My App</h1>
<DarkModeToggle />
</div>
);
}import { DarkModeToggle } from "@gozenc/react-dark-mode-toggle";
function App() {
const handleModeChange = (mode: "light" | "dark") => {
console.log("Theme changed to:", mode);
};
return <DarkModeToggle onModeChange={handleModeChange} />;
}import { DarkModeToggle } from "@gozenc/react-dark-mode-toggle";
function App() {
return (
<DarkModeToggle
size={32}
colors={{
backgroundColor: "#e3f2fd",
backgroundColorDark: "#1565c0",
color: "#1976d2",
colorDark: "#bbdefb",
}}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
size |
number | string |
24 |
Size of the toggle in pixels |
padding |
number | string |
calc(size / 4) |
Internal padding of the toggle |
onClick |
(event: MouseEvent) => void |
- | Custom click handler |
onModeChange |
(mode: 'light' | 'dark') => void |
- | Called when theme changes |
preventDefault |
boolean |
false |
Prevent default theme switching behavior |
localStorageKey |
string |
'color-theme' |
Key used for localStorage persistence |
colors |
ColorConfig |
- | Custom color configuration |
className |
string |
- | CSS class for the component |
wrapperClassName |
string |
- | CSS class for the outer container |
darkClassName |
string |
'dark' |
CSS class to toggle for dark mode |
rootElement |
HTMLElement |
document.documentElement |
Root element to toggle dark class |
interface ColorConfig {
backgroundColor?: string; // Light mode background
backgroundColorDark?: string; // Dark mode background
color?: string; // Light mode icon color
colorDark?: string; // Dark mode icon color
colorHover?: string; // Light mode hover color
colorHoverDark?: string; // Dark mode hover color
}The component automatically:
- Detects current theme by checking for a
darkclass ondocument.documentElement - Toggles the theme by adding/removing the
darkclass - Persists preference in localStorage
- Triggers callbacks when the theme changes
The component expects your CSS to respond to the dark class on the root element:
/* Light mode styles */
body {
background-color: #ffffff;
color: #000000;
}
/* Dark mode styles */
.dark body {
background-color: #1a1a1a;
color: #ffffff;
}- Modern browsers with Shadow DOM support
- React 17.0.0 or higher
- Graceful degradation for older browsers
To run the development environment:
# Clone the repository
git clone https://github.com/gozenc/react-dark-mode-toggle.git
cd react-dark-mode-toggle
# Install dependencies
npm install
# Start development server
npm run devTest the built package locally before publishing:
npm run test:browserOpens test-dist.html which:
- β
Loads the built
dist/index.jsdirectly - β Shows bundle size and gzipped size
- β Tests different component configurations
- β Uses React from CDN (simulates real usage)
- β Verifies no react-jsx-runtime is included
npm run test:localComprehensive test that:
- β
Builds the package (
npm run build) - β
Packs it like npm would (
npm pack) - β Extracts and verifies all required files
- β Checks bundle size and content
- β Confirms react-jsx-runtime is excluded
- β Validates package structure for publishing
npm run testBasic test that verifies:
- β
dist/index.jsexists - β
dist/index.d.tsexists - β Package.json configuration
-
Build the optimized package:
npm run build
-
Test in browser (visual verification):
npm run test:browser
-
Full package validation:
npm run test:local
-
If all tests pass, you're ready to publish!
After optimization:
- Bundle size: 4.56 KB
- Gzipped size: 1.76 KB
- No react-jsx-runtime: β Excluded from bundle
- All tests passing: β
Contributions are welcome! Please feel free to submit a Pull Request.
MIT Β© gozenc
- Initial release
- Beautiful animated toggle component
- Full TypeScript support
- Zero dependencies
- Customizable colors and sizes
- LocalStorage persistence
- Accessibility features
