UNPKG

preline

Version:

Preline UI is an open-source set of prebuilt UI components based on the utility-first Tailwind CSS framework.

380 lines (280 loc) 17.6 kB
# Overlay The Overlay Tailwind plugin is an unstyled JavaScript utility for creating modals, drawers, and more, enhancing user interaction and content layout. [![npm](https://img.shields.io/badge/npm-v4.2.0-blue)](https://www.npmjs.com/package/@preline/overlay) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![Demo](https://img.shields.io/badge/demo-online-brightgreen)](https://preline.co/plugins/overlay.html) ## Contents - [Overview](#overview) - [Installation](#installation) - [Basic usage](#basic-usage) - [Configuration Options](#configuration-options) - [JavaScript API](#javascript-api) - [Events](#events) - [Common Patterns](#common-patterns) - [License](#license) ## Overview The Overlay component provides a flexible foundation for creating modals, drawers, sidebars, and other overlay-based UI elements. It handles backdrop management, focus trapping, keyboard navigation, and z-index stacking automatically. **Key Features:** - Modal and drawer support - Automatic backdrop management - Focus trapping and keyboard navigation (Tab, Esc) - Z-index stacking for multiple overlays - Responsive breakpoint support - Auto-close on screen size changes - Programmatic control via JavaScript API - Event system for lifecycle hooks - Accessibility attributes (ARIA) built-in ## Installation To get started, install Overlay plugin via npm, else you can skip this step if you are already using Preline UI as a package. ```bash npm i @preline/overlay ``` ### CSS Use [`@source`](https://tailwindcss.com/docs/functions-and-directives#source-directive) to register the plugin's JavaScript path for Tailwind CSS scanning, then [`@import`](https://tailwindcss.com/docs/functions-and-directives#import-directive) the plugin's CSS files into your Tailwind CSS file. ```css @import "tailwindcss"; /* @preline/overlay */ @source "../node_modules/@preline/overlay/*.js"; @import "./node_modules/@preline/overlay/variants.css"; @import "./node_modules/@preline/overlay/theme.css"; ``` ### JavaScript Include the JavaScript that powers the interactive elements near the end of your `</body>` tag: ```html <script src="./node_modules/@preline/overlay/index.js"></script> ``` ### Manual Initialization Use the `non-auto` entry if you need manual initialization. In this mode, automatic initialization on page load is not included, so the component should be initialized explicitly. ```html <script type="module"> import HSOverlay from "@preline/overlay/non-auto.mjs"; new HSOverlay(document.querySelector("#overlay")); </script> ``` ### Via Bundler When using a bundler (Vite, webpack, etc.), import the plugin directly as an ES module. `@preline/overlay` is the auto-init entry: it scans the DOM and initializes matching elements automatically. ```js import "@preline/overlay"; ``` `@preline/overlay/non-auto` is the manual entry: use it when you want explicit control over when initialization happens, either via `autoInit()` or by creating a specific instance yourself. ```js import HSOverlay from "@preline/overlay/non-auto"; HSOverlay.autoInit(); // Or initialize a specific element manually const el = document.querySelector("#overlay"); if (el) new HSOverlay(el); ``` ### TypeScript This package ships with TypeScript type definitions. No additional `@types/` package is needed. ## Basic usage The following example demonstrates the minimal HTML structure required for an overlay component. This is a base template without custom styling - you can apply your own CSS classes and styles as needed. The overlay appears when the button is clicked. ```html <button type="button" aria-haspopup="dialog" aria-expanded="false" aria-controls="hs-unstyled-modal" data-hs-overlay="#hs-unstyled-modal"> Open modal </button> <div id="hs-unstyled-modal" class="hs-overlay hidden size-full fixed top-0 start-0 z-60 overflow-x-hidden overflow-y-auto pointer-events-none" role="dialog" tabindex="-1" aria-labelledby="hs-unstyled-modal-label"> <div class="hs-overlay-open:opacity-100 hs-overlay-open:duration-500 opacity-0 transition-all sm:max-w-lg sm:w-full m-3 sm:mx-auto"> <div class="pointer-events-auto"> <h3 id="hs-unstyled-modal-label">Title</h3> Modal content </div> </div> </div> ``` **Structure Requirements:** - `data-hs-overlay`: Required on the trigger button, must be a valid CSS selector pointing to the overlay element - `hs-overlay`: Required class on the overlay content container - `hidden` class on the overlay initially - Proper ARIA attributes (`aria-haspopup`, `aria-expanded`, `aria-controls`, `role="dialog"`, `aria-labelledby`) **Initial State:** - Set `aria-expanded="false"` on the trigger button initially - Add `hidden` class to the overlay initially - Overlay visibility is controlled by the plugin ## Configuration Options ### Data Attributes Data attributes are added directly to HTML elements to configure overlay behavior. | Attribute | Target Element | Type | Default | Description | | --- | --- | --- | --- | --- | | `data-hs-overlay-options` | Trigger button | object (JSON) | - | Defines the modal configuration. Should be added to the button (trigger). | | `:hiddenClass` | Inside `data-hs-overlay-options` | string | `"hidden"` | Defines which classes will be added/removed when modal toggles. | | `:emulateScrollbarSpace` | Inside `data-hs-overlay-options` | boolean | `false` | If `true`, then adds right padding to the body equal to the size of the scrollbar. Useful to prevent layout shift when overlay opens. | | `:isClosePrev` | Inside `data-hs-overlay-options` | boolean | `true` | Determines whether the previous open modal will be closed when the next one is opened. | | `:backdropClasses` | Inside `data-hs-overlay-options` | string | `"hs-overlay-backdrop transition duration fixed inset-0 bg-gray-900/50 dark:bg-neutral-900/80"` | Defines default backdrop classes. | | `:backdropExtraClasses` | Inside `data-hs-overlay-options` | string | - | Allows to add additional classes besides those specified in `backdropClasses`. | | `:backdropParent` | Inside `data-hs-overlay-options` | string | - | Allows to specify the selector of the element where the backdrop will be generated. | | `:moveOverlayToBody` | Inside `data-hs-overlay-options` | number \| null | `null` | Moves the overlay to the body tag if the screen width is less than the value specified. | | `:isToggleClassesImmediately` | Inside `data-hs-overlay-options` | boolean | `false` | When set to `true`, toggles `hidden`, `open`, and `opened` classes immediately instead of waiting for the open delay, resize debounce, or close transition. | | `data-hs-overlay-backdrop-container` | Overlay content | string (CSS selector) | `null` | Backdrop element selector. Should be added to the overlay (content). | | `data-hs-overlay-keyboard` | Overlay content | boolean | `true` | When set to `false`, the modal will not close when pressing the ESC button on the keyboard. Should be added to the overlay (content). | ### CSS Classes (Modifiers) CSS class modifiers use Tailwind-style syntax with `--` prefix to control overlay behavior. | Class Modifier | Target Element | Values | Default | Description | | --- | --- | --- | --- | --- | | `[--overlay-backdrop:*]` | Overlay content | `"static"` \| null | `null` | When backdrop is set to `"static"`, the modal will not close when clicking outside it. Should be added to the overlay (content). | | `[--auto-hide:*]` | Overlay content | number | `0` | Milliseconds for auto-closing a modal. When set to `0`, the modal will not close automatically. Should be added to the overlay (content). | | `[--auto-close:*]` | Overlay content | `'sm'` \| `'md'` \| `'lg'` \| `'xl'` \| `'2xl'` \| number | `null` | Screen resolution at which the overlay will close automatically. Should be added to the overlay (content). | | `[--auto-close-equality-type:*]` | Overlay content | `'less-than'` \| null | `null` | This option determines the condition under which an overlay should automatically close based on the window's width. When set to `less-than`, the overlay will close if the window's width is less than or equal to the value defined in `[--auto-close:*]`. Otherwise the overlay will close if the window's width is greater than or equal to the `[--auto-close:*]` threshold. Should be added to the overlay (content). | | `[--opened:*]` | Overlay content | `'sm'` \| `'md'` \| `'lg'` \| `'xl'` \| `'2xl'` \| number | `null` | Screen resolution at which the plugin will apply functionality for the initially opened overlay. Should be added to the overlay (content). | | `[--body-scroll:*]` | Overlay content | boolean | `true` | When set to `false`, the body scroll will be hidden as soon as the modal opens. Should be added to the overlay (content). | | `[--tab-accessibility-limited:*]` | Overlay content | `"true"` \| `"false"` | `"true"` | Restricts focus to elements within an overlay (or modal). Should be added to the overlay (content). | | `[--has-autofocus:*]` | Overlay content | `"true"` \| `"false"` | `"true"` | Disables autofocus on the first focusable element when opening an overlay. Should be added to the overlay (content). | | `[--has-dynamic-z-index:*]` | Overlay content | `"true"` \| `"false"` | `"false"` | When set to `"true"`, each newly opened element in the group will receive an incremented `z-index` inline, ensuring it appears above previously opened elements with the same base `z-index`. Should be added to the overlay (content). | | `[--is-layout-affect:*]` | Overlay content | `"true"` \| `"false"` | `"false"` | Informs the plugin that the instance affects the website layout. Should be added to the overlay (content). | | `[--toggle-classes-immediately:*]` | Overlay content | `"true"` \| `"false"` | `"false"` | When set to `"true"`, toggles `hidden`, `open`, and `opened` classes immediately instead of waiting for the open delay, resize debounce, or close transition. | **Example:** ```html <div class="hs-overlay --overlay-backdrop:static --auto-hide:5000"> <!-- Overlay content --> </div> ``` ### Required CSS Classes These classes define the structure and must be present for the overlay to function. | Class | Required On | Purpose | | --- | --- | --- | | `hs-overlay` | Overlay content container | Identifies the overlay content element | ### Optional CSS Classes | Class | Required On | Purpose | | --- | --- | --- | | `hs-overlay-animation-target` | Element inside overlay | Defines an element inside the popup, after the end of whose animation the popup will be completely hidden. Has no parameters. | | `autofocus` | Input element inside overlay | Focus the first input in a modal with the `autofocus` attribute on opening. Must be added to an input element inside a modal window. | ### Tailwind Modifiers | Name | Description | | --- | --- | | `hs-overlay-open:*` | Defines classes that will be applied to any elements inside the `hs-overlay` when the overlay is open. | | `hs-overlay-backdrop-open:*` | Defines classes that will be applied to backdrop when the overlay is open. | | `hs-overlay-layout-open:*` | Defines classes that will be applied to any elements inside the body tag when the overlay is open. | ## JavaScript API The `HSOverlay` object is available in the global `window` object after the plugin is loaded. ### Instance Methods These methods are called on an overlay instance. | Method | Parameters | Return Type | Description | | --- | --- | --- | --- | | `open(cb)` | `cb`: `Function \| null` (optional) | `Promise<void>` | Forces the overlay to open programmatically. Optionally accepts a callback function that will be called after opening. Returns a Promise. | | `close(forceClose, cb)` | `forceClose`: `boolean` (optional)<br>`cb`: `Function \| null` (optional) | `Promise<unknown>` | Forces the overlay to close programmatically. `forceClose` bypasses animations and closes immediately. Optionally accepts a callback function. Returns a Promise. | | `minify(isMinified, cb)` | `isMinified`: `boolean`<br>`cb`: `Function \| null` (optional) | `void` | Minimizes or restores the overlay. Useful for drawer/sidebar components. | | `updateToggles()` | None | `void` | Updates the toggle buttons. Useful after dynamically adding or removing toggle buttons. | | `destroy()` | None | `void` | Destroys the overlay instance, removes all generated markup, classes, and event listeners. Use when removing overlay from DOM. | ### Static Methods These methods are called directly on the `HSOverlay` class. | Method | Parameters | Return Type | Description | | --- | --- | --- | --- | | `HSOverlay.getInstance(target, isInstance)` | `target`: `HTMLElement \| string` (CSS selector)<br>`isInstance`: `boolean` (optional) | `HTMLElement \| { id: string \| number, element: HSOverlay } \| null` | Returns the overlay instance or element associated with the target. If `isInstance` is `true`, returns collection item object `{ id, element }` where `element` is the `HSOverlay` instance. If `isInstance` is `false` or omitted, returns the DOM element (`HTMLElement`). Returns `null` if overlay instance is not found. | | `HSOverlay.open(target)` | `target`: `HSOverlay \| HTMLElement \| string` (CSS selector) | `void` | Opens the overlay identified by target. Accepts an overlay instance, DOM element, or CSS selector string. Static alternative to instance `open()` method. | | `HSOverlay.close(target)` | `target`: `HSOverlay \| HTMLElement \| string` (CSS selector) | `void` | Closes the overlay identified by target. Accepts an overlay instance, DOM element, or CSS selector string. Static alternative to instance `close()` method. | ### Usage Examples **Example 1: Using instance methods (public API)** ```javascript // Create a new overlay instance const modal = new HSOverlay(document.querySelector('#hs-modal')); const openBtn = document.querySelector('#hs-open-btn'); // Open overlay programmatically openBtn.addEventListener('click', () => { modal.open(); }); ``` **Example 2: Using static methods** ```javascript const openBtn = document.querySelector('#hs-open-btn'); // Open overlay using static method (no instance needed) openBtn.addEventListener('click', () => { HSOverlay.open('#hs-modal'); }); ``` **Example 3: Getting instance and using methods (recommended pattern)** ```javascript // Get the overlay instance const instance = HSOverlay.getInstance('#hs-modal', true); if (instance) { const { element } = instance; // element is the HSOverlay instance const openBtn = document.querySelector('#hs-open-btn'); const closeBtn = document.querySelector('#hs-close-btn'); // Use instance methods openBtn.addEventListener('click', () => { element.open(); }); closeBtn.addEventListener('click', () => { element.close(); }); // Clean up when removing from DOM function removeOverlay() { element.destroy(); } } ``` **Example 4: Destroying overlay instance** ```javascript const instance = HSOverlay.getInstance('#hs-modal', true); if (instance) { const { element } = instance; const removeBtn = document.querySelector('#hs-remove-btn'); removeBtn.addEventListener('click', () => { // Clean up before removing from DOM element.destroy(); // Now safe to remove the element document.querySelector('#hs-modal').remove(); }); } ``` ## Events Overlay instances emit events that can be listened to for lifecycle hooks and custom behavior. | Event Name | When Fired | Callback Parameter | Description | | --- | --- | --- | --- | | `on:open` | After overlay is opened | `HSOverlay` (overlay instance) | Fires after the overlay has been displayed. Use for post-open actions like loading content or focusing elements. | | `on:close` | After overlay is closed | `HSOverlay` (overlay instance) | Fires after the overlay has been hidden. Use for cleanup or state updates. | ### Event Usage Example ```javascript // Get overlay instance const instance = HSOverlay.getInstance('#hs-modal', true); if (instance) { const { element } = instance; // Listen to open event element.on('open', (overlayInstance) => { console.log('Overlay opened:', overlayInstance); // Perform actions after overlay opens // e.g., load content, focus input, track analytics }); // Listen to close event element.on('close', (overlayInstance) => { console.log('Overlay closed:', overlayInstance); // Perform cleanup or state updates }); } ``` ## Common Patterns ### Pattern 1: Static Backdrop Prevent closing when clicking outside the overlay. ```html <div class="hs-overlay --overlay-backdrop:static"> <!-- Overlay content --> </div> ``` ### Pattern 2: Auto-close on Screen Size Close overlay automatically at specific breakpoints. ```html <div class="hs-overlay --auto-close:md --auto-close-equality-type:less-than"> <!-- Overlay content --> </div> ``` ### Pattern 3: Programmatic Control Control overlay from external buttons. ```html <button id="hs-open-modal">Open Modal</button> <button id="hs-close-modal">Close Modal</button> <div id="hs-modal-first" class="hs-overlay hidden"> <!-- Overlay content --> </div> <script> const instance = HSOverlay.getInstance('#hs-modal-first', true); if (instance) { const { element } = instance; document.querySelector('#hs-open-modal').addEventListener('click', () => { element.open(); }); document.querySelector('#hs-close-modal').addEventListener('click', () => { element.close(); }); } </script> ``` ## License Copyright (c) 2026 Preline Labs. Licensed under the [MIT License](https://opensource.org/licenses/MIT).