Skip to content

Commit 286f26a

Browse files
feat(FOUC): Add script to prevent theme flash
1 parent 7afbe0e commit 286f26a

File tree

6 files changed

+62
-97
lines changed

6 files changed

+62
-97
lines changed

README.md

Lines changed: 27 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[![Downloads](https://img.shields.io/npm/dm/@angularui/theme.svg)](https://www.npmjs.com/package/@angularui/theme)
55
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
66

7-
> **Modern Theme Management for Angular** - A lightweight, feature-rich theme library with automatic dark mode detection, SSR support, and zero configuration required.
7+
Modern Theme Management for Angular - A lightweight, feature-rich theme library with automatic dark mode detection, SSR support, and zero configuration required.
88

99
**🌐 [Live Demo](https://angularcafe.github.io/angularui-theme/)**
1010

@@ -97,27 +97,24 @@ body {
9797
}
9898
```
9999

100-
## 🎯 Why @angularui/theme?
101-
102-
### For Angular Developers
103-
104-
- **Native Angular Integration** - Built specifically for Angular with signals, dependency injection, and modern patterns
105-
- **TypeScript First** - Full type safety with comprehensive TypeScript support
106-
- **Angular 20+ Ready** - Uses latest Angular features like signals and standalone components
107-
- **Modern DI Pattern** - Uses Angular's inject() function for better performance and tree-shaking
108-
- **Future-Proof** - Built with Angular's latest patterns and best practices
109-
- **Enterprise Ready** - Designed for large-scale applications with proper error handling
110-
- **Clean Architecture** - Uses app initializer for testable, flexible initialization
100+
### How to Prevent Theme Flash (FOUC) with an Inline Script
101+
Add this **inline** script to your `index.html` `<head>`:
102+
```html
103+
<script>
104+
(function(){'use strict';try{var t=localStorage.getItem('theme')||'system',e=t==='system'?window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light':t==='light'||t==='dark'?t:'light',n=document.documentElement;if(n){n.classList.remove('light','dark'),e==='dark'?(n.classList.add('dark'),n.setAttribute('data-theme','dark')):(n.classList.remove('dark'),n.removeAttribute('data-theme')),n.style.colorScheme=e}}catch(e){try{var n=document.documentElement;n&&(n.classList.remove('light','dark'),n.removeAttribute('data-theme'),n.style.colorScheme='light')}catch(e){}}})();
105+
</script>
106+
```
107+
**Why inline?** Angular does not provide a way to inject scripts into the HTML `<head>` at build time. For true FOUC prevention, the script must run immediately as the HTML is parsed—before any content is rendered. External scripts or Angular providers/services run too late to prevent a flash. This is why the script must be copied directly into your `index.html` head.
111108

112-
### Benefits for Angular Ecosystem
109+
## Why @angularui/theme?
113110

114-
- **Consistent Theming** - Standardized approach across Angular applications
115-
- **Developer Experience** - Excellent IDE support with full autocomplete
116-
- **Performance** - Leverages Angular's signal system for optimal reactivity
117-
- **Maintainability** - Clean, well-documented API following Angular conventions
118-
- **Community** - Contributes to Angular's rich ecosystem of tools
119-
- **Reduced Bundle Size** - Tree-shakeable and optimized for production
120-
- **Better Testing** - App initializer pattern enables easier unit testing
111+
- Native Angular integration: signals, DI, and standalone components
112+
- TypeScript-first and future-proof (Angular 20+ ready)
113+
- Clean, testable architecture (app initializer pattern)
114+
- Consistent, standardized theming across apps
115+
- Excellent developer experience (autocomplete, IDE support)
116+
- Performance optimized and tree-shakeable
117+
- Well-documented, maintainable, and enterprise-ready
121118

122119
## 🏗️ Modern Architecture
123120

@@ -167,33 +164,28 @@ interface ThemeConfig {
167164
#### Tailwind CSS Integration
168165
```typescript
169166
provideUiTheme({
170-
strategy: 'class',
171-
defaultTheme: 'system',
172-
enableColorScheme: true
167+
strategy: 'class'
173168
})
174169
```
175170

176171
#### Custom Storage Key
177172
```typescript
178173
provideUiTheme({
179-
storageKey: 'my-app-theme',
180-
defaultTheme: 'dark'
174+
storageKey: 'my-app-theme'
181175
})
182176
```
183177

184178
#### Disable System Detection
185179
```typescript
186180
provideUiTheme({
187-
enableSystem: false,
188-
defaultTheme: 'light'
181+
enableSystem: false
189182
})
190183
```
191184

192185
#### Forced Theme (for demos)
193186
```typescript
194187
provideUiTheme({
195-
forcedTheme: 'dark',
196-
enableAutoInit: true
188+
forcedTheme: 'dark'
197189
})
198190
```
199191

@@ -405,23 +397,14 @@ effect(() => {
405397

406398
## 🤝 Contributing
407399

408-
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
400+
Contributions are welcome! To contribute:
409401

410-
### Development
402+
1. **Fork** this repository.
403+
2. **Create a new branch** for your feature or fix.
404+
3. **Make your changes** and ensure all tests pass.
405+
4. **Open a Pull Request** with a clear description of your changes.
411406

412-
```bash
413-
# Clone the repository
414-
git clone https://github.com/angularcafe/angularui-theme.git
415-
416-
# Install dependencies
417-
npm install
418-
419-
# Run tests
420-
npm test
421-
422-
# Build the package
423-
npm run build
424-
```
407+
Please review our [Contributing Guide](CONTRIBUTING.md) before submitting your PR.
425408

426409
## 📄 License
427410

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"start": "ng serve",
77
"build": "ng build",
88
"build:demo": "ng build demo --configuration production --base-href /angularui-theme/",
9+
"build:theme": "ng build theme --configuration production",
910
"watch": "ng build --watch --configuration development",
1011
"test": "ng test"
1112
},
@@ -45,4 +46,4 @@
4546
"ng-packagr": "^20.1.0",
4647
"typescript": "~5.8.2"
4748
}
48-
}
49+
}

projects/demo/src/index.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
<base href="/">
88
<meta name="viewport" content="width=device-width, initial-scale=1">
99
<link rel="icon" type="image/x-icon" href="favicon.ico">
10+
11+
<!-- Flash Prevention - Prevents FOUC in all browsers -->
12+
<script>
13+
(function(){'use strict';try{var t=localStorage.getItem('theme')||'system',e=t==='system'?window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light':t==='light'||t==='dark'?t:'light',n=document.documentElement;if(n){n.classList.remove('light','dark'),e==='dark'?(n.classList.add('dark'),n.setAttribute('data-theme','dark')):(n.classList.remove('dark'),n.removeAttribute('data-theme')),n.style.colorScheme=e}}catch(e){try{var n=document.documentElement;n&&(n.classList.remove('light','dark'),n.removeAttribute('data-theme'),n.style.colorScheme='light')}catch(e){}}})();
14+
</script>
1015
</head>
1116

1217
<body>

projects/demo/src/styles.css

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
html {
4747
background-color: var(--bg-primary);
4848
color: var(--text-primary);
49-
transition: background-color 0.3s ease, color 0.3s ease;
5049
}
5150

5251
body {
@@ -57,11 +56,5 @@ body {
5756
sans-serif;
5857
background-color: var(--bg-primary);
5958
color: var(--text-primary);
60-
transition: background-color 0.3s ease, color 0.3s ease;
6159
line-height: 1.6;
6260
}
63-
64-
/* Smooth transitions for theme changes */
65-
* {
66-
transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease;
67-
}

projects/theme/README.md

Lines changed: 27 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[![Downloads](https://img.shields.io/npm/dm/@angularui/theme.svg)](https://www.npmjs.com/package/@angularui/theme)
55
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
66

7-
> **Modern Theme Management for Angular** - A lightweight, feature-rich theme library with automatic dark mode detection, SSR support, and zero configuration required.
7+
Modern Theme Management for Angular - A lightweight, feature-rich theme library with automatic dark mode detection, SSR support, and zero configuration required.
88

99
**🌐 [Live Demo](https://angularcafe.github.io/angularui-theme/)**
1010

@@ -97,27 +97,24 @@ body {
9797
}
9898
```
9999

100-
## 🎯 Why @angularui/theme?
101-
102-
### For Angular Developers
103-
104-
- **Native Angular Integration** - Built specifically for Angular with signals, dependency injection, and modern patterns
105-
- **TypeScript First** - Full type safety with comprehensive TypeScript support
106-
- **Angular 20+ Ready** - Uses latest Angular features like signals and standalone components
107-
- **Modern DI Pattern** - Uses Angular's inject() function for better performance and tree-shaking
108-
- **Future-Proof** - Built with Angular's latest patterns and best practices
109-
- **Enterprise Ready** - Designed for large-scale applications with proper error handling
110-
- **Clean Architecture** - Uses app initializer for testable, flexible initialization
100+
### How to Prevent Theme Flash (FOUC) with an Inline Script
101+
Add this **inline** script to your `index.html` `<head>`:
102+
```html
103+
<script>
104+
(function(){'use strict';try{var t=localStorage.getItem('theme')||'system',e=t==='system'?window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light':t==='light'||t==='dark'?t:'light',n=document.documentElement;if(n){n.classList.remove('light','dark'),e==='dark'?(n.classList.add('dark'),n.setAttribute('data-theme','dark')):(n.classList.remove('dark'),n.removeAttribute('data-theme')),n.style.colorScheme=e}}catch(e){try{var n=document.documentElement;n&&(n.classList.remove('light','dark'),n.removeAttribute('data-theme'),n.style.colorScheme='light')}catch(e){}}})();
105+
</script>
106+
```
107+
**Why inline?** Angular does not provide a way to inject scripts into the HTML `<head>` at build time. For true FOUC prevention, the script must run immediately as the HTML is parsed—before any content is rendered. External scripts or Angular providers/services run too late to prevent a flash. This is why the script must be copied directly into your `index.html` head.
111108

112-
### Benefits for Angular Ecosystem
109+
## Why @angularui/theme?
113110

114-
- **Consistent Theming** - Standardized approach across Angular applications
115-
- **Developer Experience** - Excellent IDE support with full autocomplete
116-
- **Performance** - Leverages Angular's signal system for optimal reactivity
117-
- **Maintainability** - Clean, well-documented API following Angular conventions
118-
- **Community** - Contributes to Angular's rich ecosystem of tools
119-
- **Reduced Bundle Size** - Tree-shakeable and optimized for production
120-
- **Better Testing** - App initializer pattern enables easier unit testing
111+
- Native Angular integration: signals, DI, and standalone components
112+
- TypeScript-first and future-proof (Angular 20+ ready)
113+
- Clean, testable architecture (app initializer pattern)
114+
- Consistent, standardized theming across apps
115+
- Excellent developer experience (autocomplete, IDE support)
116+
- Performance optimized and tree-shakeable
117+
- Well-documented, maintainable, and enterprise-ready
121118

122119
## 🏗️ Modern Architecture
123120

@@ -167,33 +164,28 @@ interface ThemeConfig {
167164
#### Tailwind CSS Integration
168165
```typescript
169166
provideUiTheme({
170-
strategy: 'class',
171-
defaultTheme: 'system',
172-
enableColorScheme: true
167+
strategy: 'class'
173168
})
174169
```
175170

176171
#### Custom Storage Key
177172
```typescript
178173
provideUiTheme({
179-
storageKey: 'my-app-theme',
180-
defaultTheme: 'dark'
174+
storageKey: 'my-app-theme'
181175
})
182176
```
183177

184178
#### Disable System Detection
185179
```typescript
186180
provideUiTheme({
187-
enableSystem: false,
188-
defaultTheme: 'light'
181+
enableSystem: false
189182
})
190183
```
191184

192185
#### Forced Theme (for demos)
193186
```typescript
194187
provideUiTheme({
195-
forcedTheme: 'dark',
196-
enableAutoInit: true
188+
forcedTheme: 'dark'
197189
})
198190
```
199191

@@ -405,23 +397,14 @@ effect(() => {
405397

406398
## 🤝 Contributing
407399

408-
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
400+
Contributions are welcome! To contribute:
409401

410-
### Development
402+
1. **Fork** this repository.
403+
2. **Create a new branch** for your feature or fix.
404+
3. **Make your changes** and ensure all tests pass.
405+
4. **Open a Pull Request** with a clear description of your changes.
411406

412-
```bash
413-
# Clone the repository
414-
git clone https://github.com/angularcafe/angularui-theme.git
415-
416-
# Install dependencies
417-
npm install
418-
419-
# Run tests
420-
npm test
421-
422-
# Build the package
423-
npm run build
424-
```
407+
Please review our [Contributing Guide](CONTRIBUTING.md) before submitting your PR.
425408

426409
## 📄 License
427410

projects/theme/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@angularui/theme",
3-
"version": "0.0.4",
3+
"version": "0.1.0",
44
"description": "Modern Theme Management for Angular - A lightweight, feature-rich theme library with automatic dark mode detection, SSR support, and zero configuration required.",
55
"keywords": [
66
"angular",

0 commit comments

Comments
 (0)