or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

cards.mdindex.mdlayout-navigation.mdplugins.mdsearch.mdstyling.mdutilities.mdwidgets.md
tile.json

widgets.mddocs/

Interactive Widgets

AdminLTE provides several interactive widgets including treeview navigation, expandable tables, todo lists, and direct chat interfaces. These components enhance the user experience with dynamic content and intuitive interactions.

Treeview

The Treeview component provides hierarchical navigation with collapsible menu items, supporting nested navigation structures and accordion-style behavior.

API

class Treeview {
  constructor(element: HTMLElement, options?: TreeviewOptions);
  init(): void;
  expand(treeviewMenu: HTMLElement, parentLi: HTMLElement): void;
  collapse(treeviewMenu: HTMLElement, parentLi: HTMLElement): void;
  toggle(event: Event): void;
}

interface TreeviewOptions {
  trigger?: string;
  animationSpeed?: number;
  accordion?: boolean;
  expandSidebar?: boolean;
  sidebarButtonSelector?: string;
}

Default Configuration

const TreeviewDefaults = {
  trigger: '[data-widget="treeview"] .nav-link',
  animationSpeed: 300,
  accordion: true,
  expandSidebar: false,
  sidebarButtonSelector: '[data-widget="pushmenu"]'
};

Events

// Event types triggered by Treeview
type TreeviewEvents = 
  | 'expanded.lte.treeview'
  | 'collapsed.lte.treeview'
  | 'load.lte.treeview';

Usage Examples

Programmatic Usage

import { Treeview } from 'admin-lte';

// Initialize treeview
const treeElement = document.querySelector('[data-widget="treeview"]');
const treeview = new Treeview(treeElement, {
  animationSpeed: 250,
  accordion: true,
  expandSidebar: true
});

// Control programmatically
treeview.init();

// Listen for events
document.addEventListener('expanded.lte.treeview', function(event) {
  console.log('Tree node expanded:', event.target);
});

Data Attribute Usage

<!-- Sidebar navigation with treeview -->
<nav class="mt-2">
  <ul class="nav nav-pills nav-sidebar flex-column" 
      data-widget="treeview" 
      role="menu" 
      data-accordion="false">
    
    <!-- Simple menu item -->
    <li class="nav-item">
      <a href="dashboard.html" class="nav-link active">
        <i class="nav-icon fas fa-tachometer-alt"></i>
        <p>Dashboard</p>
      </a>
    </li>
    
    <!-- Menu item with submenu -->
    <li class="nav-item">
      <a href="#" class="nav-link">
        <i class="nav-icon fas fa-users"></i>
        <p>
          User Management
          <i class="fas fa-angle-left right"></i>
        </p>
      </a>
      <ul class="nav nav-treeview">
        <li class="nav-item">
          <a href="users.html" class="nav-link">
            <i class="far fa-circle nav-icon"></i>
            <p>All Users</p>
          </a>
        </li>
        <li class="nav-item">
          <a href="roles.html" class="nav-link">
            <i class="far fa-circle nav-icon"></i>
            <p>User Roles</p>
          </a>
        </li>
        <li class="nav-item">
          <a href="permissions.html" class="nav-link">
            <i class="far fa-circle nav-icon"></i>
            <p>Permissions</p>
          </a>
        </li>
      </ul>
    </li>
    
    <!-- Multi-level nested menu -->
    <li class="nav-item">
      <a href="#" class="nav-link">
        <i class="nav-icon fas fa-cogs"></i>
        <p>
          Settings
          <i class="fas fa-angle-left right"></i>
        </p>
      </a>
      <ul class="nav nav-treeview">
        <li class="nav-item">
          <a href="#" class="nav-link">
            <i class="far fa-circle nav-icon"></i>
            <p>
              System Settings
              <i class="fas fa-angle-left right"></i>
            </p>
          </a>
          <ul class="nav nav-treeview">
            <li class="nav-item">
              <a href="general.html" class="nav-link">
                <i class="far fa-dot-circle nav-icon"></i>
                <p>General</p>
              </a>
            </li>
            <li class="nav-item">
              <a href="security.html" class="nav-link">
                <i class="far fa-dot-circle nav-icon"></i>
                <p>Security</p>
              </a>
            </li>
          </ul>
        </li>
      </ul>
    </li>
  </ul>
</nav>

TodoList

The TodoList component manages interactive todo list functionality with check/uncheck capabilities and customizable callbacks.

API

class TodoList {
  constructor(element: HTMLElement, options?: TodoListOptions);
  toggle(item: HTMLElement): void;
  check(item: HTMLElement): void;
  unCheck(item: HTMLElement): void;
}

interface TodoListOptions {
  onCheck?: (item: HTMLElement) => HTMLElement;
  onUnCheck?: (item: HTMLElement) => HTMLElement;
}

Default Configuration

const TodoListDefaults = {
  onCheck: function(item) { return item; },
  onUnCheck: function(item) { return item; }
};

Usage Examples

Programmatic Usage

import { TodoList } from 'admin-lte';

// Initialize todo list
const todoElement = document.querySelector('[data-widget="todo-list"]');
const todoList = new TodoList(todoElement, {
  onCheck(item) {
    console.log('Todo item checked:', item.textContent);
    // Send to server, update database, etc.
    return item;
  },
  onUnCheck(item) {
    console.log('Todo item unchecked:', item.textContent);
    // Update server, remove from completed list, etc.
    return item;
  }
});

// Control programmatically
const firstTodoItem = todoElement.querySelector('.todo-item');
todoList.check(firstTodoItem);
todoList.unCheck(firstTodoItem);
todoList.toggle(firstTodoItem);

Data Attribute Usage

<!-- Todo list widget -->
<div class="card">
  <div class="card-header">
    <h3 class="card-title">
      <i class="ion ion-clipboard mr-1"></i>
      To Do List
    </h3>
  </div>
  <div class="card-body">
    <ul class="todo-list" data-widget="todo-list">
      <li>
        <span class="handle">
          <i class="fas fa-ellipsis-v"></i>
          <i class="fas fa-ellipsis-v"></i>
        </span>
        <div class="icheck-primary d-inline ml-2">
          <input type="checkbox" value="" name="todo1" id="todoCheck1">
          <label for="todoCheck1"></label>
        </div>
        <span class="text">Design a nice theme</span>
        <small class="badge badge-danger">
          <i class="far fa-clock"></i> 2 mins
        </small>
        <div class="tools">
          <i class="fas fa-edit"></i>
          <i class="fas fa-trash-o"></i>
        </div>
      </li>
      
      <li>
        <span class="handle">
          <i class="fas fa-ellipsis-v"></i>
          <i class="fas fa-ellipsis-v"></i>
        </span>
        <div class="icheck-primary d-inline ml-2">
          <input type="checkbox" value="" name="todo2" id="todoCheck2" checked>
          <label for="todoCheck2"></label>
        </div>
        <span class="text">Make the theme responsive</span>
        <small class="badge badge-info">
          <i class="far fa-clock"></i> 4 hours
        </small>
        <div class="tools">
          <i class="fas fa-edit"></i>
          <i class="fas fa-trash-o"></i>
        </div>
      </li>
      
      <li>
        <span class="handle">
          <i class="fas fa-ellipsis-v"></i>
          <i class="fas fa-ellipsis-v"></i>
        </span>
        <div class="icheck-primary d-inline ml-2">
          <input type="checkbox" value="" name="todo3" id="todoCheck3">
          <label for="todoCheck3"></label>
        </div>
        <span class="text">Let theme shine like a star</span>
        <small class="badge badge-warning">
          <i class="far fa-clock"></i> 1 day
        </small>
        <div class="tools">
          <i class="fas fa-edit"></i>
          <i class="fas fa-trash-o"></i>
        </div>
      </li>
    </ul>
  </div>
  <div class="card-footer clearfix">
    <button type="button" class="btn btn-primary float-right">
      <i class="fas fa-plus"></i> Add item
    </button>
  </div>
</div>

Dynamic Todo List with Server Integration

const todoList = new TodoList(todoElement, {
  onCheck(item) {
    const todoId = item.dataset.todoId;
    const todoText = item.querySelector('.text').textContent;
    
    // Update server
    fetch('/api/todos/' + todoId, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ completed: true })
    })
    .then(response => response.json())
    .then(data => {
      console.log('Todo marked as completed:', todoText);
      // Add visual feedback
      item.classList.add('done');
    })
    .catch(error => {
      console.error('Error updating todo:', error);
      // Revert on error
      item.querySelector('input[type="checkbox"]').checked = false;
    });
    
    return item;
  },
  
  onUnCheck(item) {
    const todoId = item.dataset.todoId;
    
    // Update server
    fetch('/api/todos/' + todoId, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ completed: false })
    })
    .then(response => response.json())
    .then(data => {
      console.log('Todo marked as incomplete');
      item.classList.remove('done');
    });
    
    return item;
  }
});

ExpandableTable

The ExpandableTable component enables table rows to expand and show additional content, perfect for master-detail views and hierarchical data display.

API

class ExpandableTable {
  constructor(element: HTMLElement, options?: ExpandableTableOptions);
  init(): void;
  toggleRow(): void;
}

interface ExpandableTableOptions {
  // No specific options in default configuration
}

Events

// Event types triggered by ExpandableTable
type ExpandableTableEvents = 
  | 'expanded.lte.expandableTable'
  | 'collapsed.lte.expandableTable';

Usage Examples

Data Attribute Usage

<table class="table table-bordered">
  <thead>
    <tr>
      <th style="width: 10px">#</th>
      <th>User</th>
      <th>Date</th>
      <th>Status</th>
      <th style="width: 40px">Actions</th>
    </tr>
  </thead>
  <tbody>
    <!-- Expandable row -->
    <tr data-widget="expandable-table" aria-expanded="false">
      <td>1.</td>
      <td>John Doe</td>
      <td>11-7-2023</td>
      <td>
        <span class="badge bg-success">Active</span>
      </td>
      <td>
        <button type="button" class="btn btn-default btn-sm">
          <i class="fas fa-eye"></i>
        </button>
      </td>
    </tr>
    <!-- Expandable content -->
    <tr class="expandable-body">
      <td colspan="5">
        <div class="p-3">
          <h5>User Details</h5>
          <p><strong>Email:</strong> john.doe@example.com</p>
          <p><strong>Phone:</strong> +1 234 567 8900</p>
          <p><strong>Address:</strong> 123 Main St, City, State 12345</p>
          <p><strong>Last Login:</strong> 2023-11-07 14:30:22</p>
          <p><strong>Notes:</strong> Premium customer since 2020</p>
        </div>
      </td>
    </tr>
    
    <!-- Another expandable row -->
    <tr data-widget="expandable-table" aria-expanded="false">
      <td>2.</td>
      <td>Jane Smith</td>
      <td>10-7-2023</td>
      <td>
        <span class="badge bg-warning">Pending</span>
      </td>
      <td>
        <button type="button" class="btn btn-default btn-sm">
          <i class="fas fa-eye"></i>
        </button>
      </td>
    </tr>
    <tr class="expandable-body">
      <td colspan="5">
        <div class="p-3">
          <h5>User Details</h5>
          <p><strong>Email:</strong> jane.smith@example.com</p>
          <p><strong>Status:</strong> Account verification pending</p>
          <p><strong>Registration:</strong> 2023-10-07 09:15:33</p>
        </div>
      </td>
    </tr>
  </tbody>
</table>

Programmatic Usage

import { ExpandableTable } from 'admin-lte';

// Initialize expandable table
const tableRows = document.querySelectorAll('[data-widget="expandable-table"]');
tableRows.forEach(row => {
  const expandableTable = new ExpandableTable(row);
  expandableTable.init();
});

// Listen for events
document.addEventListener('expanded.lte.expandableTable', function(event) {
  const row = event.target;
  console.log('Row expanded:', row);
  
  // Load additional data if needed
  const userId = row.dataset.userId;
  if (userId) {
    loadUserDetails(userId);
  }
});

function loadUserDetails(userId) {
  fetch('/api/users/' + userId + '/details')
    .then(response => response.json())
    .then(data => {
      // Update the expandable content with detailed data
      const expandableBody = document.querySelector(`[data-user-id="${userId}"] + .expandable-body`);
      expandableBody.innerHTML = renderUserDetails(data);
    });
}

DirectChat

The DirectChat component provides a toggle interface for chat contact lists, enabling users to switch between chat messages and contact views.

API

class DirectChat {
  constructor(element: HTMLElement, options?: DirectChatOptions);
  toggle(): void;
}

interface DirectChatOptions {
  // No specific options in default configuration
}

Events

// Event types triggered by DirectChat
type DirectChatEvents = 'toggled.lte.directchat';

Usage Examples

Data Attribute Usage

<!-- Direct chat widget -->
<div class="card direct-chat direct-chat-primary">
  <div class="card-header">
    <h3 class="card-title">Direct Chat</h3>
    <div class="card-tools">
      <span title="3 New Messages" class="badge badge-primary">3</span>
      <button type="button" class="btn btn-tool" data-card-widget="collapse">
        <i class="fas fa-minus"></i>
      </button>
      <button type="button" class="btn btn-tool" title="Contacts" data-widget="chat-pane-toggle">
        <i class="fas fa-comments"></i>
      </button>
      <button type="button" class="btn btn-tool" data-card-widget="remove">
        <i class="fas fa-times"></i>
      </button>
    </div>
  </div>

  <div class="card-body">
    <!-- Chat messages -->
    <div class="direct-chat-messages">
      <!-- Message to the right -->
      <div class="direct-chat-msg right">
        <div class="direct-chat-infos clearfix">
          <span class="direct-chat-name float-right">Sarah Bullock</span>
          <span class="direct-chat-timestamp float-left">23 Jan 2:00 pm</span>
        </div>
        <img class="direct-chat-img" src="user-avatar.jpg" alt="message user image">
        <div class="direct-chat-text">
          You better believe it!
        </div>
      </div>

      <!-- Message to the left -->
      <div class="direct-chat-msg">
        <div class="direct-chat-infos clearfix">
          <span class="direct-chat-name float-left">Alexander Pierce</span>
          <span class="direct-chat-timestamp float-right">23 Jan 2:05 pm</span>
        </div>
        <img class="direct-chat-img" src="user2-avatar.jpg" alt="message user image">
        <div class="direct-chat-text">
          Working with AdminLTE on a great new app! Wanna join?
        </div>
      </div>
    </div>

    <!-- Contacts pane (initially hidden) -->
    <div class="direct-chat-contacts">
      <ul class="contacts-list">
        <li>
          <a href="#">
            <img class="contacts-list-img" src="user-avatar.jpg" alt="User Avatar">
            <div class="contacts-list-info">
              <span class="contacts-list-name">
                Count Dracula
                <small class="contacts-list-date float-right">2/28/2015</small>
              </span>
              <span class="contacts-list-msg">How have you been? I was...</span>
            </div>
          </a>
        </li>
      </ul>
    </div>
  </div>

  <div class="card-footer">
    <form action="#" method="post">
      <div class="input-group">
        <input type="text" name="message" placeholder="Type Message ..." class="form-control">
        <span class="input-group-append">
          <button type="button" class="btn btn-primary">Send</button>
        </span>
      </div>
    </form>
  </div>
</div>

Programmatic Usage

import { DirectChat } from 'admin-lte';

// Initialize direct chat
const chatElement = document.querySelector('[data-widget="chat-pane-toggle"]');
const directChat = new DirectChat(chatElement);

// Toggle chat pane programmatically
directChat.toggle();

// Listen for toggle events
document.addEventListener('toggled.lte.directchat', function(event) {
  console.log('Chat pane toggled');
  
  // Update contact list when pane is shown
  const chatWidget = event.target.closest('.direct-chat');
  const contactsPane = chatWidget.querySelector('.direct-chat-contacts');
  
  if (contactsPane.style.display !== 'none') {
    loadChatContacts();
  }
});

function loadChatContacts() {
  fetch('/api/chat/contacts')
    .then(response => response.json())
    .then(contacts => {
      renderContactList(contacts);
    });
}

All interactive widgets provide:

  • Smooth animations and transitions
  • Event-driven architecture for custom integrations
  • Accessible keyboard navigation
  • Customizable styling through SCSS variables
  • Data attribute initialization for easy setup