UNPKG

preline

Version:

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

341 lines (252 loc) 13 kB
# Tree View Tree View solutions for massive datasets. [![npm](https://img.shields.io/badge/npm-v4.2.0-blue)](https://www.npmjs.com/package/@preline/tree-view) [![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/tree-view.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 Tree View component provides a hierarchical structure for displaying nested data, similar to file explorers. It integrates with the Accordion component to create expandable/collapsible tree nodes and supports both checkbox and button selection modes. **Key Features:** - Hierarchical nested structure - Expandable/collapsible nodes (using Accordion) - Multiple selection modes (checkbox, button) - Auto-select children option for directories - Programmatic control via JavaScript API - Event system for selection tracking - Accessibility attributes (ARIA) built-in ## Installation To get started, install Tree View plugin via npm, else you can skip this step if you are already using Preline UI as a package. ```bash npm i @preline/tree-view @preline/accordion ``` ### 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/accordion */ @source "../node_modules/@preline/accordion/*.js"; @import "./node_modules/@preline/accordion/variants.css"; /* @preline/tree-view */ @source "../node_modules/@preline/tree-view/*.js"; @import "./node_modules/@preline/tree-view/variants.css"; @import "./node_modules/@preline/tree-view/theme.css"; ``` ### JavaScript Include the JavaScript that powers the interactive elements near the end of your `</body>` tag: ```html <script src="./node_modules/@preline/accordion/index.js"></script> <script src="./node_modules/@preline/tree-view/index.js"></script> ``` ### Manual Initialization Use the `non-auto` entry if you need manual initialization. Tree View depends on Accordion for expand/collapse behavior, so call `HSAccordion.autoInit()` first and then initialize the specific Tree View element manually. ```html <script type="module"> import HSAccordion from "@preline/accordion/non-auto.mjs"; import HSTreeView from "@preline/tree-view/non-auto.mjs"; HSAccordion.autoInit(); new HSTreeView(document.querySelector("#tree-view")); </script> ``` ### Via Bundler When using a bundler (Vite, webpack, etc.), import the plugin directly as an ES module. Initialize `HSAccordion` first, since it powers the expand/collapse nodes inside the tree. The first example uses the auto-init entries. This means the plugins scan the DOM and initialize matching elements automatically. The second example uses the manual `non-auto` entries. Use this when you want explicit control over initialization order and timing, or when you need to initialize a specific Tree View instance yourself. ```js import "@preline/accordion"; import "@preline/tree-view"; ``` ```js import HSAccordion from "@preline/accordion/non-auto"; import HSTreeView from "@preline/tree-view/non-auto"; // Initialize all matching accordion nodes first HSAccordion.autoInit(); // Then initialize all matching tree views HSTreeView.autoInit(); // Or initialize a specific element manually const el = document.querySelector("#tree-view"); if (el) new HSTreeView(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 a tree view component. This is a base template without custom styling - you can apply your own CSS classes and styles as needed. The example shows a directory structure with expandable folders and files. ```html <div role="tree" aria-orientation="vertical" data-hs-tree-view> <div class="hs-accordion active" role="treeitem" aria-expanded="true" id="hs-tree-view-heading-first" data-hs-tree-view-item='{ "value": "assets", "isDir": true }'> <div class="hs-accordion-heading"> <button class="hs-accordion-toggle" aria-expanded="true" aria-controls="hs-tree-view-collapse-first"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path class="hs-accordion-active:hidden block" d="M12 5v14"/></svg> </button> assets </div> <div id="hs-tree-view-collapse-first" class="hs-accordion-content overflow-hidden transition-[height] duration-300" role="group" aria-labelledby="hs-tree-view-heading-first"> <div role="treeitem" data-hs-tree-view-item='{ "value": "image.jpg" }'>image.jpg</div> </div> </div> </div> ``` **Structure Requirements:** - `data-hs-tree-view`: Required on the root container element - `role="tree"`: Required on the root container - `aria-orientation="vertical"`: Required on the root container - `hs-accordion`: Required for each directory/folder node - `data-hs-tree-view-item`: Required on each tree item (files and directories) - Proper ARIA attributes (`role="treeitem"`, `aria-expanded`, `aria-controls`, `aria-labelledby`) **Initial State:** - Directories can be expanded/collapsed using accordion functionality - Items can be selected based on the `controlBy` mode ## Configuration Options ### Data Options Data options are specified in the `data-hs-tree-view` and `data-hs-tree-view-item` attributes. | Attribute | Target Element | Type | Default | Description | | --- | --- | --- | --- | --- | | `data-hs-tree-view` | Root container | - | - | Activate a Tree View by specifying on an element. Should be added to the wrapper container. | | `:controlBy` | Inside `data-hs-tree-view` | `"checkbox"` \| `"button"` | `"button"` | Tells the plugin which mode is active and processes events accordingly. `checkbox` mode allows multiple selections, `button` mode allows single selection. | | `:autoSelectChildren` | Inside `data-hs-tree-view` | boolean | `false` | This option is available if `controlBy` is set to `checkbox` and if the item is a directory (`isDir: true`). When `true`, if a parent directory is selected, all nested items receive the same selection state. | | `:isIndeterminate` | Inside `data-hs-tree-view` | boolean | `true` | Adds indeterminate visual style for checkboxes when `controlBy` is set to `checkbox`. Shows when some but not all children are selected. | | `data-hs-tree-view-item` | Each tree item | - | - | Determines which element inside the initialized component is the item. Should be added to the item itself. | | `:id` | Inside `data-hs-tree-view-item` | string | - | Optional. Desired identifier for the item. | | `:value` | Inside `data-hs-tree-view-item` | string | - | The value that will be passed to the resulting array when item is selected. | | `:isDir` | Inside `data-hs-tree-view-item` | boolean | `false` | Determines that the element is a directory and processes it accordingly. Directories can contain nested items. | **Example:** ```html <div data-hs-tree-view='{ "controlBy": "checkbox", "autoSelectChildren": true, "isIndeterminate": true }'> <!-- Tree items --> </div> ``` ### Tailwind Modifiers | Name | Description | | --- | --- | | `hs-tree-view-selected:*` | A modifier that allows you to set Tailwind classes when item has been selected. | | `hs-tree-view-disabled:*` | A modifier that allows you to set Tailwind classes when item has "disabled" class. | ## JavaScript API The `HSTreeView` object is available in the global `window` object after the plugin is loaded. ### Instance Methods These methods are called on a tree view instance. | Method | Parameters | Return Type | Description | | --- | --- | --- | --- | | `update()` | None | `void` | Updates the element. This is suitable, for example, in case of changing the order of elements or dynamically adding/removing items. | | `getSelectedItems()` | None | `ITreeViewItem[]` | Returns a list of selected items as an array of objects with item properties. | | `changeItemProp(id, prop, val)` | `id`: `string`<br>`prop`: `string`<br>`val`: `any` | `void` | Changes a property of a specific item. Useful for updating item state programmatically. | | `destroy()` | None | `void` | Destroys the tree view instance, removes all generated markup, classes, and event listeners. Use when removing tree view from DOM. | ### Static Methods These methods are called directly on the `HSTreeView` class. | Method | Parameters | Return Type | Description | | --- | --- | --- | --- | | `HSTreeView.getInstance(target, isInstance)` | `target`: `HTMLElement \| string` (CSS selector)<br>`isInstance`: `boolean` (optional) | `HTMLElement \| { id: string \| number, element: HSTreeView } \| null` | Returns the tree view instance or element associated with the target. If `isInstance` is `true`, returns collection item object `{ id, element }` where `element` is the `HSTreeView` instance. If `isInstance` is `false` or omitted, returns the DOM element (`HTMLElement`). Returns `null` if tree view instance is not found. | ### Usage Examples **Example 1: Getting selected items** ```javascript // Get the tree view instance const instance = HSTreeView.getInstance('#hs-tree-view', true); if (instance) { const { element } = instance; // Get all selected items const selectedItems = element.getSelectedItems(); console.log('Selected items:', selectedItems); } ``` **Example 2: Updating tree view after dynamic changes** ```javascript const instance = HSTreeView.getInstance('#hs-tree-view', true); if (instance) { const { element } = instance; // After adding or removing items dynamically element.update(); } ``` **Example 3: Changing item properties programmatically** ```javascript const instance = HSTreeView.getInstance('#hs-tree-view', true); if (instance) { const { element } = instance; // Change item property element.changeItemProp('item-id', 'isSelected', true); } ``` **Example 4: Destroying tree view instance** ```javascript const instance = HSTreeView.getInstance('#hs-tree-view', 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-tree-view').remove(); }); } ``` ## Events Tree view instances emit events that can be listened to for selection tracking and custom behavior. | Event Name | When Fired | Callback Parameter | Description | | --- | --- | --- | --- | | `on:click` | When any item is selected | `{ id: string, value: string, isDir: boolean, path: string, isSelected: boolean }` | Fires when an item is clicked/selected. Returns an object with:<br>- `id`: Item identifier<br>- `value`: Item value<br>- `isDir`: Whether item is a directory<br>- `path`: Path to the item<br>- `isSelected`: Whether item is currently selected | ### Event Usage Example ```javascript // Get tree view instance const instance = HSTreeView.getInstance('#hs-tree-view', true); if (instance) { const { element } = instance; // Listen to click event element.on('click', ({ id, value, isDir, path, isSelected }) => { console.log('Item clicked:', { id, value, isDirectory: isDir, path, isSelected }); // Perform actions after item selection // e.g., update UI, track analytics, load content }); } ``` ## Common Patterns ### Pattern 1: Checkbox Mode with Auto-select Children Enable checkbox selection with automatic child selection. ```html <div data-hs-tree-view='{ "controlBy": "checkbox", "autoSelectChildren": true }'> <!-- Tree items --> </div> ``` ### Pattern 2: Getting Selected Items Retrieve all selected items programmatically. ```html <div id="hs-tree-view-first" data-hs-tree-view> <!-- Tree items --> </div> <button id="hs-get-selected">Get Selected</button> <script> const instance = HSTreeView.getInstance('#hs-tree-view-first', true); if (instance) { const { element } = instance; document.querySelector('#hs-get-selected').addEventListener('click', () => { const selected = element.getSelectedItems(); console.log('Selected items:', selected); }); } </script> ``` ## License Copyright (c) 2026 Preline Labs. Licensed under the [MIT License](https://opensource.org/licenses/MIT).