Skip to main content

Building Admin Dashboards with Tabler

Introduction

Tabler is a free and open-source admin dashboard template built on top of Bootstrap 5. It provides a modern, responsive UI kit with over 300+ components, making it perfect for building professional admin panels, dashboards, and web applications.

Why Choose Tabler?

  • Free and Open Source: MIT licensed, completely free to use
  • Built on Bootstrap 5: Leverages the power and flexibility of Bootstrap
  • 300+ Components: Extensive library of pre-built UI components
  • Responsive Design: Works seamlessly across all devices
  • Modern UI/UX: Clean, professional interface design
  • Well-Documented: Comprehensive documentation at docs.tabler.io
  • Active Community: Regular updates and community support
  • Multiple Versions: Available in HTML, React, Vue, and other frameworks

What You'll Build

In this tutorial, you'll learn how to create a fully functional admin dashboard with:

  • User authentication and management
  • Data tables and charts
  • Forms and validation
  • Navigation and routing
  • Responsive layouts
  • Custom components

Getting Started

Prerequisites

Before you begin, make sure you have:

  • Basic knowledge of HTML, CSS, and JavaScript
  • A code editor (VS Code, Sublime Text, etc.)
  • Node.js installed (for package management)
  • A modern web browser

Installation Methods

Method 1: Download from Website

  1. Visit https://tabler.io/admin-template
  2. Click the "Download" button to get the latest version
  3. Extract the ZIP file to your project directory
  4. Open index.html in your browser to see the demo
# Install Tabler via npm
npm install @tabler/core

# Or using yarn
yarn add @tabler/core

Method 3: Using CDN

For quick prototyping, you can use the CDN links:

<!DOCTYPE html>
<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/@tabler/core@latest/dist/css/tabler.min.css" rel="stylesheet"/>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/@tabler/core@latest/dist/js/tabler.min.js"></script>
</body>
</html>

Method 4: Clone from GitHub

# Clone the repository
git clone https://github.com/tabler/tabler.git
cd tabler

# Install dependencies
npm install

# Start development server
npm run start

Basic Dashboard Layout

Understanding the Structure

A typical Tabler dashboard consists of several key components:

  1. Page Wrapper: The main container
  2. Header/Navbar: Top navigation bar
  3. Sidebar: Side navigation menu
  4. Page Content: Main content area
  5. Footer: Bottom section

Creating a Basic Layout

Here's a minimal dashboard structure:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>My Admin Dashboard</title>
<link href="https://cdn.jsdelivr.net/npm/@tabler/core@latest/dist/css/tabler.min.css" rel="stylesheet"/>
</head>
<body>
<div class="page">
<!-- Navbar -->
<header class="navbar navbar-expand-md d-print-none">
<div class="container-xl">
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbar-menu">
<span class="navbar-toggler-icon"></span>
</button>
<h1 class="navbar-brand navbar-brand-autodark d-none-navbar-horizontal pe-0 pe-md-3">
<a href=".">
<img src="./static/logo.svg" width="110" height="32" alt="Tabler" class="navbar-brand-image">
</a>
</h1>
<div class="navbar-nav flex-row order-md-last">
<div class="nav-item dropdown">
<a href="#" class="nav-link d-flex lh-1 text-reset p-0" data-bs-toggle="dropdown">
<span class="avatar avatar-sm">JL</span>
<div class="d-none d-xl-block ps-2">
<div>John Doe</div>
<div class="mt-1 small text-muted">Administrator</div>
</div>
</a>
<div class="dropdown-menu dropdown-menu-end">
<a class="dropdown-item" href="#">Profile</a>
<a class="dropdown-item" href="#">Settings</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Logout</a>
</div>
</div>
</div>
</div>
</header>

<!-- Page Wrapper -->
<div class="page-wrapper">
<!-- Page Header -->
<div class="page-header d-print-none">
<div class="container-xl">
<div class="row g-2 align-items-center">
<div class="col">
<h2 class="page-title">Dashboard</h2>
</div>
</div>
</div>
</div>

<!-- Page Body -->
<div class="page-body">
<div class="container-xl">
<!-- Your content here -->
</div>
</div>
</div>
</div>

<script src="https://cdn.jsdelivr.net/npm/@tabler/core@latest/dist/js/tabler.min.js"></script>
</body>
</html>

Adding a Sidebar

For a more complex layout with a sidebar:

<div class="page">
<!-- Sidebar -->
<aside class="navbar navbar-vertical navbar-expand-lg" data-bs-theme="dark">
<div class="container-fluid">
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#sidebar-menu">
<span class="navbar-toggler-icon"></span>
</button>
<h1 class="navbar-brand navbar-brand-autodark">
<a href=".">
<img src="./static/logo-white.svg" width="110" height="32" alt="Tabler">
</a>
</h1>
<div class="collapse navbar-collapse" id="sidebar-menu">
<ul class="navbar-nav pt-lg-3">
<li class="nav-item">
<a class="nav-link" href="./index.html">
<span class="nav-link-icon d-md-none d-lg-inline-block">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none">
<path stroke="linecap" round="stroke-linejoin="round" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
</svg>
</span>
<span class="nav-link-title">Dashboard</span>
</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#navbar-extra" data-bs-toggle="dropdown" role="button">
<span class="nav-link-icon d-md-none d-lg-inline-block">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none">
<path stroke="linecap" round="stroke-linejoin="round" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z" />
</svg>
</span>
<span class="nav-link-title">Users</span>
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="./users-list.html">User List</a>
<a class="dropdown-item" href="./users-add.html">Add User</a>
</div>
</li>
</ul>
</div>
</div>
</aside>

<!-- Main content -->
<div class="page-wrapper">
<!-- Content goes here -->
</div>
</div>

Working with Components

Dashboard Cards

Cards are the building blocks of your dashboard. Here's how to create statistical cards:

<div class="container-xl">
<div class="row row-deck row-cards">
<!-- Total Revenue Card -->
<div class="col-sm-6 col-lg-3">
<div class="card">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="subheader">Total Revenue</div>
</div>
<div class="h1 mb-3">$75,893</div>
<div class="d-flex mb-2">
<div>Response Rate</div>
<div class="ms-auto">
<span class="text-green d-inline-flex align-items-center lh-1">
14%
<svg xmlns="http://www.w3.org/2000/svg" class="icon ms-1" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none">
<path stroke="linecap" round="stroke-linejoin="round" d="M3 17l6-6 4 4 8-8" />
<path stroke="linecap" round="stroke-linejoin="round" d="M14 7h7v7" />
</svg>
</span>
</div>
</div>
<div class="progress progress-sm">
<div class="progress-bar bg-primary" style="width: 75%" role="progressbar"></div>
</div>
</div>
</div>
</div>

<!-- Users Card -->
<div class="col-sm-6 col-lg-3">
<div class="card">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="subheader">Total Users</div>
</div>
<div class="h1 mb-3">2,847</div>
<div class="d-flex mb-2">
<div>New this month</div>
<div class="ms-auto">
<span class="text-green d-inline-flex align-items-center lh-1">
8%
<svg xmlns="http://www.w3.org/2000/svg" class="icon ms-1" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none">
<path stroke="linecap" round="stroke-linejoin="round" d="M3 17l6-6 4 4 8-8" />
</svg>
</span>
</div>
</div>
<div class="progress progress-sm">
<div class="progress-bar bg-primary" style="width: 60%" role="progressbar"></div>
</div>
</div>
</div>
</div>
</div>
</div>

Data Tables

Create professional data tables with sorting and pagination:

<div class="card">
<div class="card-header">
<h3 class="card-title">User Management</h3>
</div>
<div class="card-body border-bottom py-3">
<div class="d-flex">
<div class="text-muted">
Show
<div class="mx-2 d-inline-block">
<input type="text" class="form-control form-control-sm" value="8" size="3">
</div>
entries
</div>
<div class="ms-auto text-muted">
Search:
<div class="ms-2 d-inline-block">
<input type="text" class="form-control form-control-sm">
</div>
</div>
</div>
</div>
<div class="table-responsive">
<table class="table card-table table-vcenter text-nowrap datatable">
<thead>
<tr>
<th class="w-1"><input class="form-check-input m-0 align-middle" type="checkbox"></th>
<th>Name</th>
<th>Email</th>
<th>Role</th>
<th>Status</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td><input class="form-check-input m-0 align-middle" type="checkbox"></td>
<td>
<div class="d-flex py-1 align-items-center">
<span class="avatar me-2">JL</span>
<div class="flex-fill">
<div class="font-weight-medium">John Doe</div>
<div class="text-muted">Joined 2 months ago</div>
</div>
</div>
</td>
<td>john.doe@example.com</td>
<td>Admin</td>
<td>
<span class="badge bg-success me-1"></span>
Active
</td>
<td>
<div class="btn-list flex-nowrap">
<button class="btn btn-sm">Edit</button>
<button class="btn btn-sm btn-danger">Delete</button>
</div>
</td>
</tr>
<tr>
<td><input class="form-check-input m-0 align-middle" type="checkbox"></td>
<td>
<div class="d-flex py-1 align-items-center">
<span class="avatar me-2">JS</span>
<div class="flex-fill">
<div class="font-weight-medium">Jane Smith</div>
<div class="text-muted">Joined 1 month ago</div>
</div>
</div>
</td>
<td>jane.smith@example.com</td>
<td>User</td>
<td>
<span class="badge bg-success me-1"></span>
Active
</td>
<td>
<div class="btn-list flex-nowrap">
<button class="btn btn-sm">Edit</button>
<button class="btn btn-sm btn-danger">Delete</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="card-footer d-flex align-items-center">
<p class="m-0 text-muted">Showing <span>1</span> to <span>8</span> of <span>16</span> entries</p>
<ul class="pagination m-0 ms-auto">
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none">
<path stroke="linecap" round="stroke-linejoin="round" d="M15 19l-7-7 7-7" />
</svg>
prev
</a>
</li>
<li class="page-item active"><a class="page-link" href="#">1</a></li>
<li class="page-item"><a class="page-link" href="#">2</a></li>
<li class="page-item"><a class="page-link" href="#">3</a></li>
<li class="page-item">
<a class="page-link" href="#">
next
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none">
<path stroke="linecap" round="stroke-linejoin="round" d="M9 5l7 7-7 7" />
</svg>
</a>
</li>
</ul>
</div>
</div>

Forms

Create beautiful, accessible forms:

<div class="card">
<div class="card-header">
<h3 class="card-title">Add New User</h3>
</div>
<div class="card-body">
<div class="mb-3">
<label class="form-label required">Full Name</label>
<input type="text" class="form-control" placeholder="Enter full name">
</div>
<div class="mb-3">
<label class="form-label required">Email address</label>
<input type="email" class="form-control" placeholder="Email">
<small class="form-hint">We'll never share your email with anyone else.</small>
</div>
<div class="mb-3">
<label class="form-label">Password</label>
<input type="password" class="form-control" placeholder="Password">
</div>
<div class="mb-3">
<label class="form-label">Role</label>
<select class="form-select">
<option value="1">Admin</option>
<option value="2">User</option>
<option value="3">Guest</option>
</select>
</div>
<div class="mb-3">
<label class="form-label">Bio</label>
<textarea class="form-control" rows="3" placeholder="Tell us about yourself"></textarea>
</div>
<div class="form-footer">
<button type="submit" class="btn btn-primary">Create User</button>
<button type="button" class="btn">Cancel</button>
</div>
</div>
</div>

Modals

Add interactive modals to your dashboard:

<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modal-report">
Open Modal
</button>

<!-- Modal -->
<div class="modal modal-blur fade" id="modal-report" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">New report</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label class="form-label">Name</label>
<input type="text" class="form-control" name="example-text-input" placeholder="Your report name">
</div>
<label class="form-label">Report type</label>
<div class="form-selectgroup-boxes row mb-3">
<div class="col-lg-6">
<label class="form-selectgroup-item">
<input type="radio" name="report-type" value="1" class="form-selectgroup-input" checked>
<span class="form-selectgroup-label d-flex align-items-center p-3">
<span class="me-3">
<span class="form-selectgroup-check"></span>
</span>
<span class="form-selectgroup-label-content">
<span class="form-selectgroup-title strong mb-1">Simple</span>
<span class="d-block text-muted">Provide only basic data needed for the report</span>
</span>
</span>
</label>
</div>
<div class="col-lg-6">
<label class="form-selectgroup-item">
<input type="radio" name="report-type" value="1" class="form-selectgroup-input">
<span class="form-selectgroup-label d-flex align-items-center p-3">
<span class="me-3">
<span class="form-selectgroup-check"></span>
</span>
<span class="form-selectgroup-label-content">
<span class="form-selectgroup-title strong mb-1">Advanced</span>
<span class="d-block text-muted">Insert additional data for the report</span>
</span>
</span>
</label>
</div>
</div>
</div>
<div class="modal-footer">
<a href="#" class="btn btn-link link-secondary" data-bs-dismiss="modal">
Cancel
</a>
<a href="#" class="btn btn-primary ms-auto" data-bs-dismiss="modal">
Create new report
</a>
</div>
</div>
</div>
</div>

Charts and Data Visualization

Tabler integrates well with popular charting libraries. Here's how to add charts using ApexCharts:

Installing ApexCharts

<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>

Creating a Line Chart

<div class="card">
<div class="card-header">
<h3 class="card-title">Sales Overview</h3>
</div>
<div class="card-body">
<div id="chart-demo-line"></div>
</div>
</div>

<script>
document.addEventListener("DOMContentLoaded", function () {
window.ApexCharts && (new ApexCharts(document.getElementById('chart-demo-line'), {
chart: {
type: "line",
fontFamily: 'inherit',
height: 240,
parentHeightOffset: 0,
toolbar: {
show: false,
},
animations: {
enabled: false
},
},
fill: {
opacity: 1,
},
stroke: {
width: 2,
lineCap: "round",
curve: "smooth",
},
series: [{
name: "Sales",
data: [37, 35, 44, 28, 36, 24, 65, 31, 37, 39, 62, 51]
}],
grid: {
padding: {
top: -20,
right: 0,
left: -4,
bottom: -4
},
strokeDashArray: 4,
},
xaxis: {
labels: {
padding: 0,
},
tooltip: {
enabled: false
},
type: 'datetime',
},
yaxis: {
labels: {
padding: 4
},
},
labels: [
'2020-06-20', '2020-06-21', '2020-06-22', '2020-06-23', '2020-06-24',
'2020-06-25', '2020-06-26', '2020-06-27', '2020-06-28', '2020-06-29',
'2020-06-30', '2020-07-01'
],
colors: ["#206bc4"],
legend: {
show: false,
},
})).render();
});
</script>

Creating a Pie Chart

<div class="card">
<div class="card-header">
<h3 class="card-title">Traffic Sources</h3>
</div>
<div class="card-body">
<div id="chart-demo-pie"></div>
</div>
</div>

<script>
document.addEventListener("DOMContentLoaded", function () {
window.ApexCharts && (new ApexCharts(document.getElementById('chart-demo-pie'), {
chart: {
type: "donut",
fontFamily: 'inherit',
height: 240,
sparkline: {
enabled: true
},
animations: {
enabled: false
},
},
fill: {
opacity: 1,
},
series: [44, 55, 12, 19],
labels: ["Direct", "Organic Search", "Social Media", "Referral"],
grid: {
strokeDashArray: 4,
},
colors: ["#206bc4", "#79a6dc", "#bfe399", "#e9ecf1"],
legend: {
show: true,
position: 'bottom',
offsetY: 12,
markers: {
width: 10,
height: 10,
radius: 100,
},
itemMargin: {
horizontal: 8,
vertical: 8
},
},
tooltip: {
fillSeriesColor: false
},
})).render();
});
</script>

Creating a Multi-Page Application

For a multi-page dashboard, organize your files:

my-dashboard/
├── index.html (Dashboard home)
├── users.html (User management)
├── settings.html (Settings page)
├── profile.html (User profile)
├── css/
│ └── custom.css
├── js/
│ └── main.js
└── img/
└── ...

Active Navigation States

Highlight the current page in navigation:

<ul class="navbar-nav pt-lg-3">
<li class="nav-item">
<a class="nav-link active" href="./index.html">
<span class="nav-link-icon d-md-none d-lg-inline-block">
<svg><!-- icon --></svg>
</span>
<span class="nav-link-title">Dashboard</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="./users.html">
<span class="nav-link-icon d-md-none d-lg-inline-block">
<svg><!-- icon --></svg>
</span>
<span class="nav-link-title">Users</span>
</a>
</li>
</ul>

Use JavaScript to automatically set active states:

// Set active navigation item based on current page
document.addEventListener('DOMContentLoaded', function() {
const currentPath = window.location.pathname;
const navLinks = document.querySelectorAll('.nav-link');

navLinks.forEach(link => {
if (link.getAttribute('href') === currentPath) {
link.classList.add('active');
}
});
});

Customization and Theming

Using Custom CSS

Create a custom stylesheet to override Tabler defaults:

/* custom.css */

/* Custom color scheme */
:root {
--tblr-primary: #4299e1;
--tblr-secondary: #6c757d;
--tblr-success: #48bb78;
--tblr-danger: #f56565;
}

/* Custom card styling */
.card {
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
}

/* Custom button styles */
.btn-primary {
background-color: var(--tblr-primary);
border-color: var(--tblr-primary);
}

.btn-primary:hover {
background-color: #3182ce;
border-color: #3182ce;
}

/* Custom navbar */
.navbar-brand-autodark {
filter: brightness(0) invert(1);
}

Include it in your HTML:

<head>
<link href="https://cdn.jsdelivr.net/npm/@tabler/core@latest/dist/css/tabler.min.css" rel="stylesheet"/>
<link href="./css/custom.css" rel="stylesheet"/>
</head>

Dark Mode

Tabler includes built-in dark mode support:

<!-- Add data-bs-theme attribute -->
<html data-bs-theme="dark">
<!-- or -->
<div data-bs-theme="dark">
<!-- Dark mode content -->
</div>

Toggle dark mode with JavaScript:

function toggleDarkMode() {
const html = document.documentElement;
const currentTheme = html.getAttribute('data-bs-theme');
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
html.setAttribute('data-bs-theme', newTheme);
localStorage.setItem('theme', newTheme);
}

// Load saved theme on page load
document.addEventListener('DOMContentLoaded', function() {
const savedTheme = localStorage.getItem('theme') || 'light';
document.documentElement.setAttribute('data-bs-theme', savedTheme);
});

Add a theme toggle button:

<button class="btn btn-icon" onclick="toggleDarkMode()">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none">
<path stroke="linecap" round="stroke-linejoin="round" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
</svg>
</button>

Integration with Backend/API

Fetching Data from API

Example of loading data from a REST API:

// Fetch users from API
async function loadUsers() {
try {
const response = await fetch('https://api.example.com/users');
const users = await response.json();

const tbody = document.querySelector('.users-table tbody');
tbody.innerHTML = '';

users.forEach(user => {
const row = `
<tr>
<td>
<div class="d-flex py-1 align-items-center">
<span class="avatar me-2">${user.initials}</span>
<div class="flex-fill">
<div class="font-weight-medium">${user.name}</div>
<div class="text-muted">Joined ${user.joinDate}</div>
</div>
</div>
</td>
<td>${user.email}</td>
<td>${user.role}</td>
<td>
<span class="badge bg-${user.active ? 'success' : 'danger'}">
${user.active ? 'Active' : 'Inactive'}
</span>
</td>
<td>
<button class="btn btn-sm" onclick="editUser(${user.id})">Edit</button>
<button class="btn btn-sm btn-danger" onclick="deleteUser(${user.id})">Delete</button>
</td>
</tr>
`;
tbody.innerHTML += row;
});
} catch (error) {
console.error('Error loading users:', error);
showNotification('Error loading users', 'danger');
}
}

// Call on page load
document.addEventListener('DOMContentLoaded', loadUsers);

Submitting Forms

Handle form submissions with API calls:

document.querySelector('#user-form').addEventListener('submit', async function(e) {
e.preventDefault();

const formData = {
name: document.querySelector('#name').value,
email: document.querySelector('#email').value,
role: document.querySelector('#role').value,
bio: document.querySelector('#bio').value
};

try {
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + getAuthToken()
},
body: JSON.stringify(formData)
});

if (response.ok) {
showNotification('User created successfully', 'success');
document.querySelector('#user-form').reset();
loadUsers(); // Reload the user list
} else {
showNotification('Error creating user', 'danger');
}
} catch (error) {
console.error('Error:', error);
showNotification('Network error', 'danger');
}
});

Notifications

Show user feedback with toast notifications:

function showNotification(message, type = 'info') {
const toast = document.createElement('div');
toast.className = `alert alert-${type} alert-dismissible`;
toast.innerHTML = `
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
`;

const container = document.querySelector('.page-body .container-xl');
container.insertBefore(toast, container.firstChild);

// Auto-dismiss after 5 seconds
setTimeout(() => {
toast.remove();
}, 5000);
}

Authentication and User Management

Login Page

Create a beautiful login page:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Login - Admin Dashboard</title>
<link href="https://cdn.jsdelivr.net/npm/@tabler/core@latest/dist/css/tabler.min.css" rel="stylesheet"/>
</head>
<body class="d-flex flex-column">
<div class="page page-center">
<div class="container container-tight py-4">
<div class="text-center mb-4">
<a href="." class="navbar-brand navbar-brand-autodark">
<img src="./static/logo.svg" width="110" height="32" alt="Tabler">
</a>
</div>
<div class="card card-md">
<div class="card-body">
<h2 class="h2 text-center mb-4">Login to your account</h2>
<form action="./" method="post" autocomplete="off">
<div class="mb-3">
<label class="form-label">Email address</label>
<input type="email" class="form-control" placeholder="your@email.com" autocomplete="off">
</div>
<div class="mb-2">
<label class="form-label">
Password
<span class="form-label-description">
<a href="./forgot-password.html">I forgot password</a>
</span>
</label>
<div class="input-group input-group-flat">
<input type="password" class="form-control" placeholder="Your password" autocomplete="off">
<span class="input-group-text">
<a href="#" class="link-secondary" title="Show password">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none">
<path stroke="linecap" round="stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
<path stroke="linecap" round="stroke-linejoin="round" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
</svg>
</a>
</span>
</div>
</div>
<div class="mb-2">
<label class="form-check">
<input type="checkbox" class="form-check-input"/>
<span class="form-check-label">Remember me on this device</span>
</label>
</div>
<div class="form-footer">
<button type="submit" class="btn btn-primary w-100">Sign in</button>
</div>
</form>
</div>
<div class="hr-text">or</div>
<div class="card-body">
<div class="row">
<div class="col">
<a href="#" class="btn w-100">
<svg xmlns="http://www.w3.org/2000/svg" class="icon text-github" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none">
<path stroke="linecap" round="stroke-linejoin="round" d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 00-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0020 4.77 5.07 5.07 0 0019.91 1S18.73.65 16 2.48a13.38 13.38 0 00-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 005 4.77a5.44 5.44 0 00-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 009 18.13V22" />
</svg>
Login with Github
</a>
</div>
<div class="col">
<a href="#" class="btn w-100">
<svg xmlns="http://www.w3.org/2000/svg" class="icon text-twitter" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none">
<path stroke="linecap" round="stroke-linejoin="round" d="M23 3a10.9 10.9 0 01-3.14 1.53 4.48 4.48 0 00-7.86 3v1A10.66 10.66 0 013 4s-4 9 5 13a11.64 11.64 0 01-7 2c9 5 20 0 20-11.5a4.5 4.5 0 00-.08-.83A7.72 7.72 0 0023 3z" />
</svg>
Login with Twitter
</a>
</div>
</div>
</div>
</div>
<div class="text-center text-muted mt-3">
Don't have account yet? <a href="./sign-up.html" tabindex="-1">Sign up</a>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/@tabler/core@latest/dist/js/tabler.min.js"></script>
</body>
</html>

Authentication Flow

Implement authentication logic:

// Login handler
async function login(email, password) {
try {
const response = await fetch('https://api.example.com/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ email, password })
});

if (response.ok) {
const data = await response.json();
localStorage.setItem('authToken', data.token);
localStorage.setItem('user', JSON.stringify(data.user));
window.location.href = './index.html';
} else {
showNotification('Invalid credentials', 'danger');
}
} catch (error) {
console.error('Login error:', error);
showNotification('Login failed', 'danger');
}
}

// Check if user is authenticated
function isAuthenticated() {
return localStorage.getItem('authToken') !== null;
}

// Get auth token
function getAuthToken() {
return localStorage.getItem('authToken');
}

// Logout
function logout() {
localStorage.removeItem('authToken');
localStorage.removeItem('user');
window.location.href = './login.html';
}

// Protect pages - add this to pages that require authentication
document.addEventListener('DOMContentLoaded', function() {
if (!isAuthenticated() && !window.location.pathname.includes('login.html')) {
window.location.href = './login.html';
}
});

User Profile

Display user information:

<div class="nav-item dropdown">
<a href="#" class="nav-link d-flex lh-1 text-reset p-0" data-bs-toggle="dropdown">
<span class="avatar avatar-sm" id="user-avatar"></span>
<div class="d-none d-xl-block ps-2">
<div id="user-name">Loading...</div>
<div class="mt-1 small text-muted" id="user-role">User</div>
</div>
</a>
<div class="dropdown-menu dropdown-menu-end">
<a class="dropdown-item" href="./profile.html">
<svg xmlns="http://www.w3.org/2000/svg" class="icon dropdown-item-icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none">
<path stroke="linecap" round="stroke-linejoin="round" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</svg>
Profile
</a>
<a class="dropdown-item" href="./settings.html">
<svg xmlns="http://www.w3.org/2000/svg" class="icon dropdown-item-icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none">
<path stroke="linecap" round="stroke-linejoin="round" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path stroke="linecap" round="stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
Settings
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" onclick="logout()">
<svg xmlns="http://www.w3.org/2000/svg" class="icon dropdown-item-icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none">
<path stroke="linecap" round="stroke-linejoin="round" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
</svg>
Logout
</a>
</div>
</div>

<script>
// Load user data
document.addEventListener('DOMContentLoaded', function() {
const user = JSON.parse(localStorage.getItem('user') || '{}');
if (user.name) {
document.getElementById('user-name').textContent = user.name;
document.getElementById('user-role').textContent = user.role;
document.getElementById('user-avatar').textContent = user.name.split(' ').map(n => n[0]).join('');
}
});
</script>

Best Practices

1. Performance Optimization

  • Minimize HTTP Requests: Combine CSS and JS files
  • Use CDN: Load Tabler from CDN for better caching
  • Lazy Loading: Load images and charts only when needed
  • Optimize Images: Compress and use appropriate formats
  • Code Splitting: Split JavaScript into smaller chunks
// Lazy load charts
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
loadChart(entry.target);
observer.unobserve(entry.target);
}
});
});

document.querySelectorAll('.chart-container').forEach(chart => {
observer.observe(chart);
});

2. Accessibility

  • Use semantic HTML elements
  • Include proper ARIA labels
  • Ensure keyboard navigation works
  • Maintain sufficient color contrast
  • Provide alt text for images
<button class="btn btn-primary" aria-label="Save changes">
<svg aria-hidden="true"><!-- icon --></svg>
Save
</button>

3. Security

  • Validate Input: Always validate user input on both client and server
  • Use HTTPS: Always use secure connections
  • Sanitize Data: Prevent XSS attacks by sanitizing HTML
  • Implement CSRF Protection: Use tokens for form submissions
  • Secure Authentication: Use JWT or secure session management
// Simple XSS prevention
function escapeHtml(text) {
const map = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#039;'
};
return text.replace(/[&<>"']/g, m => map[m]);
}

4. Responsive Design

Test your dashboard on different screen sizes:

/* Mobile optimizations */
@media (max-width: 768px) {
.page-body {
padding: 0.5rem;
}

.card {
margin-bottom: 0.5rem;
}

.table-responsive {
font-size: 0.875rem;
}
}

5. Code Organization

Keep your code organized and maintainable:

project/
├── index.html
├── css/
│ ├── tabler.min.css
│ └── custom.css
├── js/
│ ├── tabler.min.js
│ ├── auth.js
│ ├── api.js
│ └── main.js
├── pages/
│ ├── users.html
│ ├── settings.html
│ └── profile.html
└── assets/
├── images/
└── fonts/

Advanced Features

Real-time Updates

Implement WebSocket for real-time data:

const ws = new WebSocket('wss://api.example.com/ws');

ws.onmessage = function(event) {
const data = JSON.parse(event.data);

switch(data.type) {
case 'user_online':
updateUserStatus(data.userId, 'online');
break;
case 'new_notification':
showNotification(data.message, 'info');
updateNotificationBadge();
break;
}
};

Search Functionality

Add global search:

<div class="nav-item">
<div class="input-icon">
<input type="text" class="form-control" placeholder="Search…" id="global-search">
<span class="input-icon-addon">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none">
<path stroke="linecap" round="stroke-linejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
</span>
</div>
</div>

<script>
let searchTimeout;
document.getElementById('global-search').addEventListener('input', function(e) {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => {
performSearch(e.target.value);
}, 300);
});

async function performSearch(query) {
if (query.length < 2) return;

const response = await fetch(`https://api.example.com/search?q=${encodeURIComponent(query)}`);
const results = await response.json();
displaySearchResults(results);
}
</script>

Export Data

Add export functionality:

function exportToCSV(data, filename) {
const csv = data.map(row => Object.values(row).join(',')).join('\n');
const blob = new Blob([csv], { type: 'text/csv' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
}

// Usage
document.getElementById('export-btn').addEventListener('click', function() {
const users = getUsersData(); // Get your data
exportToCSV(users, 'users.csv');
});

Deployment

Production Build

Before deploying, optimize your files:

  1. Minify CSS and JavaScript
  2. Compress images
  3. Enable caching
  4. Use a CDN for static assets

Hosting Options

  • Static Hosting: Netlify, Vercel, GitHub Pages
  • Traditional Hosting: Apache, Nginx
  • Cloud Platforms: AWS S3, Google Cloud Storage, Azure Storage

Example Nginx Configuration

server {
listen 80;
server_name your-domain.com;
root /var/www/dashboard;
index index.html;

location / {
try_files $uri $uri/ /index.html;
}

location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}

gzip on;
gzip_types text/css application/javascript application/json;
}

Troubleshooting

Common Issues

Icons Not Showing

Make sure you're including Tabler Icons:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/tabler-icons.min.css">

Ensure Bootstrap JavaScript is loaded:

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>

Responsive Issues

Check viewport meta tag:

<meta name="viewport" content="width=device-width, initial-scale=1">

Additional Resources

Official Resources

Community

  • GitHub Discussions: Ask questions and share ideas
  • GitHub Issues: Report bugs and request features
  • Twitter: Follow @tabler_ui for updates
  • Tabler React: React version of Tabler
  • Tabler Angular: Angular version of Tabler
  • Tabler Icons: 4000+ open source icons
  • Tabler Email: Email templates

Conclusion

You now have the knowledge to build professional admin dashboards with Tabler. Remember to:

  • Start with the basic layout and gradually add components
  • Keep your code organized and maintainable
  • Follow best practices for security and performance
  • Test on different devices and browsers
  • Refer to the official documentation for detailed component APIs

Happy building! 🚀