Implementing a Dynamic Overlay Component in Angular
This challenge focuses on building a reusable overlay component in Angular that can be dynamically displayed on top of other content. Overlays are commonly used for modals, tooltips, loading indicators, and other UI elements that require temporary visibility and interaction. Successfully completing this challenge will demonstrate your understanding of Angular component architecture, event handling, and DOM manipulation.
Problem Description
You are tasked with creating an Angular component called OverlayComponent that displays an overlay on top of the entire page content. The overlay should have the following features:
- Dynamic Content: The overlay should accept a component to be rendered within its content area. This component can be any valid Angular component.
- Visibility Control: The overlay should have a boolean input property (
visible) that controls its visibility. Whenvisibleistrue, the overlay should be displayed; whenfalse, it should be hidden. - Click Outside Detection: The overlay should detect clicks outside of its content area. When a click occurs outside the overlay, an event (
overlayClickedOutside) should be emitted. - Background Click Blocking: When the overlay is visible, clicks should be blocked on the underlying content, preventing interaction with elements behind the overlay.
- Accessibility: The overlay should be accessible. Ensure proper ARIA attributes are used to indicate the overlay's purpose and state.
Expected Behavior:
- When
visibleis set totrue, the overlay should appear, dimming the background and preventing interaction with the underlying content. - The component passed to the
contentinput should be rendered within the overlay's content area. - Clicking anywhere outside the overlay's content area should emit the
overlayClickedOutsideevent. - When
visibleis set tofalse, the overlay should disappear, and interaction with the underlying content should be restored.
Examples
Example 1:
Input: visible = true, content = <app-my-modal-component></app-my-modal-component>
Output: Overlay displayed, background dimmed, clicks blocked on underlying content. Clicking outside the modal component emits the overlayClickedOutside event.
Explanation: The overlay is visible, displaying the modal component. Background interaction is disabled.
Example 2:
Input: visible = false, content = <app-my-tooltip-component [message]="'Hello!'"></app-my-tooltip-component>
Output: Overlay is hidden, background is not dimmed, clicks are enabled on underlying content.
Explanation: The overlay is not visible, so the tooltip component is not displayed, and the background is interactive.
Example 3: (Edge Case - No Content)
Input: visible = true, content = null
Output: Overlay displayed, background dimmed, clicks blocked on underlying content. The overlay's content area is empty.
Explanation: The overlay is visible even without content, still blocking background interaction.
Constraints
- The overlay component should be reusable and configurable.
- The overlay should not introduce significant performance overhead.
- The component passed as
contentcan be any valid Angular component. - The overlay should be visually distinct from the underlying content (e.g., with a background color or shadow).
- The
overlayClickedOutsideevent should only be emitted when the click is genuinely outside the content component. Clicks on the overlay itself (e.g., a close button on the modal) should not trigger the event.
Notes
- Consider using Angular's
ViewContainerRefandComponentFactoryResolverto dynamically create and render the content component. - You can use CSS to style the overlay and its background.
- Think about how to handle different screen sizes and responsiveness.
- Pay close attention to accessibility best practices when implementing the overlay. Use ARIA attributes appropriately to convey the overlay's role and state to assistive technologies.
- The background dimming can be achieved using CSS (e.g., a semi-transparent overlay).
- Focus management is not required for this challenge, but is a good consideration for real-world implementations.