Dynamic Theming in Angular
Creating dynamic theming allows users to personalize the look and feel of an application without requiring code changes. This challenge focuses on building a simple Angular application with a theming system that allows switching between predefined themes (e.g., light, dark, blue) at runtime. This is a common requirement in modern web applications, enhancing user experience and accessibility.
Problem Description
You are tasked with building a basic Angular application that supports dynamic theming. The application should have a component that displays some content (e.g., a heading and a paragraph) and a theme selector (e.g., a dropdown or radio buttons). When the user selects a different theme, the application's appearance should update accordingly.
What needs to be achieved:
- Implement a theming system using CSS variables (custom properties).
- Create a theme selector component that allows users to choose from a predefined set of themes.
- Update the application's CSS variables based on the selected theme.
- Persist the selected theme in local storage so that it's remembered across sessions.
Key Requirements:
- Themes: Define at least three themes: 'light', 'dark', and 'blue'. Each theme should modify at least three CSS variables (e.g.,
--background-color,--text-color,--primary-color). - Theme Selector: The theme selector should be a reusable component.
- CSS Variables: Use CSS variables for theming. Avoid inline styles.
- Local Storage: Store the selected theme in local storage.
- Initial Theme: Load the theme from local storage on application startup. If no theme is found in local storage, default to the 'light' theme.
Expected Behavior:
- On application load, the application should apply the theme stored in local storage (or the 'light' theme if no theme is stored).
- The theme selector should display the available themes.
- When the user selects a theme from the selector, the application's appearance should immediately update to reflect the new theme.
- The selected theme should be saved to local storage.
- On subsequent application loads, the previously selected theme should be applied.
Edge Cases to Consider:
- What happens if local storage is unavailable (e.g., due to browser settings)? The application should still function, defaulting to the 'light' theme.
- How to handle potential errors when accessing local storage? (While not strictly required for this challenge, consider how you might gracefully handle errors).
Examples
Example 1:
Input: Initial state: Local storage is empty.
Output: The application loads with the 'light' theme applied. The theme selector displays 'light', 'dark', and 'blue'.
Explanation: The application defaults to the 'light' theme because no theme is found in local storage.
Example 2:
Input: User selects 'dark' theme from the theme selector.
Output: The application's background color changes to a dark shade, the text color changes to a light shade, and the primary color changes to a contrasting color, all defined in the 'dark' theme. The selected theme is saved to local storage.
Explanation: The application updates its CSS variables to match the 'dark' theme and stores the selection in local storage.
Example 3:
Input: User navigates away from the application and then returns. Local storage contains the 'blue' theme.
Output: The application loads with the 'blue' theme applied. The theme selector displays 'light', 'dark', and 'blue', with 'blue' potentially highlighted as the selected theme.
Explanation: The application retrieves the 'blue' theme from local storage and applies it.
Constraints
- Angular Version: Use Angular 14 or later.
- CSS Variables: The solution must use CSS variables for theming.
- Local Storage: The solution must use local storage to persist the theme.
- Performance: The theme switching should be reasonably performant. Avoid unnecessary DOM manipulations. The application should load quickly.
- Component Structure: The solution should be structured with at least two components: a main application component and a theme selector component.
Notes
- Consider using a service to manage the theme and handle local storage interactions. This promotes separation of concerns and testability.
- Think about how to structure your CSS to make it easy to define and manage themes.
- You don't need to create a complex UI for the theme selector; a simple dropdown or radio buttons is sufficient.
- Focus on the core theming logic and the interaction between the theme selector and the application's appearance. Styling beyond the core theme variables is not required.
- Error handling for local storage is not a primary requirement, but consider how you might handle it gracefully.