Notification just now
This is a basic toast notification message.
Primary just now
This is a primary toast notification.
Success just now
Operation completed successfully!
Error just now
An error occurred!
Warning just now
Please be careful!
Info just now
Here's some information for you.
Simple toast message without header.

Tani

Official Documentation for the Tani CSS Framework - A lightweight, utility-first CSS framework with rich component library

v1.12.0 Stable

Introduction

Tani is a modern CSS framework that provides a comprehensive set of utility classes and components to build responsive, beautiful web interfaces quickly and efficiently.

Features

  • Utility-first approach for rapid development
  • Rich component library (buttons, cards, badges, navbar, etc.)
  • Comprehensive color palette
  • Extensive utility classes for spacing, typography, and more
  • No JavaScript dependencies
  • Lightweight and performant

Browser Support

Tani supports all modern browsers:

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)

Installation

  1. Download

    Download the CSS file and include it in your project:

    <link rel="stylesheet" href="./dist/css/tani.css">

Color Palette

Tani comes with a carefully crafted color palette designed for accessibility and visual appeal.

Primary
#ffab58
Secondary
#1780b4
Dark
#24292e
Success
#28a745
Danger
#dc3545
Warning
#ffc107
Note: All colors are accessible with proper contrast ratios for text and backgrounds.

Buttons

Buttons are essential interface elements available in multiple styles and sizes.

Standard Buttons

<button class="btn btn-primary">Primary</button>
<button class="btn btn-secondary">Secondary</button>
<button class="btn btn-success">Success</button>
<button class="btn btn-danger">Danger</button>
<button class="btn btn-warning">Warning</button>
<button class="btn btn-dark">Dark</button>

Outline Buttons

<button class="btn btn-outline-primary">Primary</button>
<button class="btn btn-outline-secondary">Secondary</button>
<button class="btn btn-outline-success">Success</button>
<button class="btn btn-outline-danger">Danger</button>
<button class="btn btn-outline-warning">Warning</button>
<button class="btn btn-outline-dark">Dark</button>

Button Sizes

<button class="btn btn-primary btn-sm">Small</button>
<button class="btn btn-primary">Normal</button>
<button class="btn btn-primary btn-lg">Large</button>
<button class="btn btn-primary btn-xl">Extra Large</button>

Rounded Buttons

<button class="btn btn-primary btn-rounded">Primary</button>
<button class="btn btn-secondary btn-rounded">Secondary</button>
<button class="btn btn-success btn-rounded">Success</button>

Block Buttons

<button class="btn btn-primary btn-block">Block Button</button>

Button States

<button class="btn btn-primary" disabled>Disabled</button>
<button class="btn btn-primary">Active</button>

Button Groups

Group a series of buttons together on a single line or stack them vertically.

Basic Button Group

<div class="btn-group">
  <button class="btn btn-primary">Left</button>
  <button class="btn btn-primary">Middle</button>
  <button class="btn btn-primary">Right</button>
</div>

Mixed Button Styles

<div class="btn-group">
  <button class="btn btn-danger">Delete</button>
  <button class="btn btn-warning">Edit</button>
  <button class="btn btn-success">Save</button>
</div>

Outline Button Groups

<div class="btn-group">
  <button class="btn btn-outline-primary">One</button>
  <button class="btn btn-outline-primary">Two</button>
  <button class="btn btn-outline-primary">Three</button>
</div>

Button Group Sizes



<div class="btn-group btn-group-sm">
  <button class="btn btn-primary">Small</button>
  <button class="btn btn-primary">Small</button>
  <button class="btn btn-primary">Small</button>
</div>

<div class="btn-group">
  <button class="btn btn-primary">Normal</button>
  <button class="btn btn-primary">Normal</button>
  <button class="btn btn-primary">Normal</button>
</div>

<div class="btn-group btn-group-lg">
  <button class="btn btn-primary">Large</button>
  <button class="btn btn-primary">Large</button>
  <button class="btn btn-primary">Large</button>
</div>

Vertical Button Group

<div class="btn-group btn-group-vertical">
  <button class="btn btn-primary">Top</button>
  <button class="btn btn-primary">Middle</button>
  <button class="btn btn-primary">Bottom</button>
</div>

Button Toolbar

<div class="btn-toolbar">
  <div class="btn-group">
    <button class="btn btn-primary">1</button>
    <button class="btn btn-primary">2</button>
    <button class="btn btn-primary">3</button>
  </div>
  <div class="btn-group">
    <button class="btn btn-secondary">4</button>
    <button class="btn btn-secondary">5</button>
  </div>
  <div class="btn-group">
    <button class="btn btn-success">6</button>
  </div>
</div>

Button Group with Dropdown

<div class="btn-group">
  <button class="btn btn-primary">Action</button>
  <button class="btn btn-primary">Another</button>
  <div class="dropdown">
    <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
      Dropdown
    </button>
    <ul class="dropdown-menu">
      <li><a class="dropdown-item" href="#">Action</a></li>
      <li><a class="dropdown-item" href="#">Another action</a></li>
      <li><hr class="dropdown-divider"></li>
      <li><a class="dropdown-item" href="#">Separated link</a></li>
    </ul>
  </div>
</div>
Note: Button groups automatically handle border radius and spacing between buttons. Buttons in a group share borders for a seamless appearance.

Badges

Badges are small status indicators useful for highlighting information.

Standard Badges

Primary Secondary Success Danger Warning Dark
<span class="badge badge-primary">Primary</span>
<span class="badge badge-secondary">Secondary</span>
<span class="badge badge-success">Success</span>
<span class="badge badge-danger">Danger</span>
<span class="badge badge-warning">Warning</span>
<span class="badge badge-dark">Dark</span>

Badge Sizes

Small Normal Large
<span class="badge badge-primary badge-sm">Small</span>
<span class="badge badge-primary">Normal</span>
<span class="badge badge-primary badge-lg">Large</span>

Pill Badges

Primary Secondary Success
<span class="badge badge-primary badge-pill">Primary</span>
<span class="badge badge-secondary badge-pill">Secondary</span>
<span class="badge badge-success badge-pill">Success</span>

Cards

Cards are flexible content containers for displaying information.

Basic Card

Card Title

Some quick example text to build on the card title and make up the bulk of the card's content.

Go somewhere
<div class="card">
  <div class="card-body">
    <h5 class="card-title">Card Title</h5>
    <p class="card-text">Some quick example text...</p>
    <a href="#" class="btn btn-primary">Go somewhere</a>
  </div>
</div>

Card with Header and Footer

Featured
Special title treatment

With supporting text below as a natural lead-in to additional content.

Go somewhere
<div class="card">
  <div class="card-header">
    Featured
  </div>
  <div class="card-body">
    <h5 class="card-title">Special title treatment</h5>
    <p class="card-text">With supporting text...</p>
    <a href="#" class="btn btn-primary">Go somewhere</a>
  </div>
  <div class="card-footer text-muted">
    2 days ago
  </div>
</div>

Colored Cards

Primary Card
Primary card title

Some quick example text to build on the card title.

<div class="card card-primary">
  <div class="card-header">Primary Card</div>
  <div class="card-body">
    <h5 class="card-title">Primary card title</h5>
    <p class="card-text">Some quick example text...</p>
  </div>
</div>

Card Sizes

Small Card

This is a small card.

Large Card

This is a large card with more padding.

<div class="card card-sm">
  <div class="card-body">
    <h5 class="card-title">Small Card</h5>
    <p class="card-text">This is a small card.</p>
  </div>
</div>

<div class="card card-lg">
  <div class="card-body">
    <h5 class="card-title">Large Card</h5>
    <p class="card-text">This is a large card with more padding.</p>
  </div>
</div>

Modals

Modals are dialog boxes that overlay the main content to focus user attention on important information or actions.

Basic Modal

<button class="btn btn-primary" onclick="openModal('exampleModal')">Launch Modal</button>

<div id="exampleModal" class="modal">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">Modal Title</h5>
        <button type="button" class="modal-close" onclick="closeModal('exampleModal')">×</button>
      </div>
      <div class="modal-body">
        <p>This is a basic modal dialog. You can put any content here.</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" onclick="closeModal('exampleModal')">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>

Modal Sizes

<!-- Small Modal -->
<div class="modal-dialog modal-sm">...</div>

<!-- Large Modal -->
<div class="modal-dialog modal-lg">...</div>

<!-- Extra Large Modal -->
<div class="modal-dialog modal-xl">...</div>

Centered Modal

<div class="modal-dialog modal-dialog-centered">
  <div class="modal-content">
    ...
  </div>
</div>

Animations

Modals include smooth fade-in and slide-down animations by default. The backdrop fades in while the modal content slides down from above with a smooth opacity transition.

Animation Details:
  • Backdrop fade: 0.3s ease transition
  • Modal slide-down: 50px translateY with opacity fade
  • Box shadow for depth perception
  • Smooth closing animation with fade-out

JavaScript

Modals require JavaScript to function. Here's the complete code with animation support:

// Open modal with animation
function openModal(modalId) {
    const modal = document.getElementById(modalId);
    if (modal) {
        modal.style.display = 'block';
        modal.classList.remove('fade-out');
        modal.offsetHeight; // Trigger reflow
        modal.classList.add('show');
        document.body.style.overflow = 'hidden';
    }
}

// Close modal with animation
function closeModal(modalId) {
    const modal = document.getElementById(modalId);
    if (modal) {
        modal.classList.add('fade-out');
        modal.classList.remove('show');
        
        setTimeout(() => {
            if (!modal.classList.contains('show')) {
                modal.style.display = 'none';
                modal.classList.remove('fade-out');
            }
        }, 300);
        
        document.body.style.overflow = '';
    }
}

// Close modal when clicking outside
document.addEventListener('click', function(event) {
    if (event.target.classList.contains('modal')) {
        closeModal(event.target.id);
    }
});

Toasts

Toasts are lightweight notifications designed to mimic push notifications.

Basic Toast

<div class="toast-container top-right">
  <div class="toast" id="basicToast">
    <div class="toast-header">
      <strong>Notification</strong>
      <small>just now</small>
      <button class="toast-close" onclick="hideToast('basicToast')">×</button>
    </div>
    <div class="toast-body">
      This is a basic toast notification message.
    </div>
  </div>
</div>

Toast Variants

<!-- Primary Toast -->
<div class="toast toast-primary">
  <div class="toast-header">
    <strong>Primary</strong>
    <small>just now</small>
    <button class="toast-close">×</button>
  </div>
  <div class="toast-body">
    This is a primary toast notification.
  </div>
</div>

<!-- Success Toast -->
<div class="toast toast-success">
  <div class="toast-header">
    <strong>Success</strong>
    <small>just now</small>
    <button class="toast-close">×</button>
  </div>
  <div class="toast-body">
    Operation completed successfully!
  </div>
</div>

<!-- Danger Toast -->
<div class="toast toast-danger">
  <div class="toast-header">
    <strong>Error</strong>
    <small>just now</small>
    <button class="toast-close">×</button>
  </div>
  <div class="toast-body">
    An error occurred!
  </div>
</div>

Toast Positions

<!-- Top Right -->
<div class="toast-container top-right">
  <div class="toast">...</div>
</div>

<!-- Top Left -->
<div class="toast-container top-left">
  <div class="toast">...</div>
</div>

<!-- Top Center -->
<div class="toast-container top-center">
  <div class="toast">...</div>
</div>

<!-- Bottom Right -->
<div class="toast-container bottom-right">
  <div class="toast">...</div>
</div>

<!-- Bottom Left -->
<div class="toast-container bottom-left">
  <div class="toast">...</div>
</div>

<!-- Bottom Center -->
<div class="toast-container bottom-center">
  <div class="toast">...</div>
</div>

Toast without Header

<div class="toast">
  <div class="toast-body">
    Simple toast message without header.
  </div>
</div>

JavaScript

Toasts require JavaScript to show and hide. Here's the complete code:

// Toast functionality
function showToast(toastId, duration = 5000) {
    const toast = document.getElementById(toastId);
    if (!toast) return;
    
    toast.classList.add('show');
    toast.classList.remove('hiding');
    
    // Auto hide after duration
    if (duration > 0) {
        setTimeout(() => {
            hideToast(toastId);
        }, duration);
    }
}

function hideToast(toastId) {
    const toast = document.getElementById(toastId);
    if (!toast) return;
    
    toast.classList.add('hiding');
    toast.classList.remove('show');
    
    // Remove hiding class after animation
    setTimeout(() => {
        toast.classList.remove('hiding');
    }, 300);
}

// Create toast dynamically
function createToast(message, type = 'primary', position = 'top-right', duration = 5000) {
    // Get or create container
    let container = document.querySelector(`.toast-container.${position}`);
    if (!container) {
        container = document.createElement('div');
        container.className = `toast-container ${position}`;
        document.body.appendChild(container);
    }
    
    // Create toast
    const toastId = 'toast-' + Date.now();
    const toast = document.createElement('div');
    toast.id = toastId;
    toast.className = `toast toast-${type}`;
    toast.innerHTML = `
        <div class="toast-header">
            <strong>${type.charAt(0).toUpperCase() + type.slice(1)}</strong>
            <small>just now</small>
            <button class="toast-close" onclick="hideToast('${toastId}')">×</button>
        </div>
        <div class="toast-body">${message}</div>
    `;
    
    container.appendChild(toast);
    
    // Show toast
    setTimeout(() => showToast(toastId, duration), 10);
    
    // Remove from DOM after hiding
    setTimeout(() => {
        if (toast.parentNode) {
            toast.parentNode.removeChild(toast);
        }
    }, duration + 500);
}
Tip: Use createToast() to dynamically generate toasts, or define them in HTML and show/hide with showToast() and hideToast().
Note: Toasts automatically hide after 5 seconds by default. You can customize the duration or set it to 0 for manual dismissal only.

Progress

Progress bars are used to visualize the completion status of tasks or processes.

Basic Progress Bar




<div class="progress">
  <div class="progress-bar" style="width: 25%"></div>
</div>

<div class="progress">
  <div class="progress-bar" style="width: 50%"></div>
</div>

<div class="progress">
  <div class="progress-bar" style="width: 75%"></div>
</div>

<div class="progress">
  <div class="progress-bar" style="width: 100%"></div>
</div>

Progress Bar with Label

25%

60%
<div class="progress">
  <div class="progress-bar" style="width: 25%">25%</div>
</div>

<div class="progress">
  <div class="progress-bar" style="width: 60%">60%</div>
</div>

Colored Progress Bars

Primary
Secondary
Success
Danger
Warning
Info
Dark
<div class="progress">
  <div class="progress-bar progress-bar-primary" style="width: 25%">Primary</div>
</div>

<div class="progress">
  <div class="progress-bar progress-bar-secondary" style="width: 35%">Secondary</div>
</div>

<div class="progress">
  <div class="progress-bar progress-bar-success" style="width: 50%">Success</div>
</div>

<div class="progress">
  <div class="progress-bar progress-bar-danger" style="width: 65%">Danger</div>
</div>

<div class="progress">
  <div class="progress-bar progress-bar-warning" style="width: 75%">Warning</div>
</div>

<div class="progress">
  <div class="progress-bar progress-bar-info" style="width: 85%">Info</div>
</div>

<div class="progress">
  <div class="progress-bar progress-bar-dark" style="width: 95%">Dark</div>
</div>

Striped Progress Bars

<div class="progress">
  <div class="progress-bar progress-bar-striped" style="width: 40%"></div>
</div>

<div class="progress">
  <div class="progress-bar progress-bar-success progress-bar-striped" style="width: 60%"></div>
</div>

<div class="progress">
  <div class="progress-bar progress-bar-danger progress-bar-striped" style="width: 80%"></div>
</div>

Animated Progress Bars

<div class="progress">
  <div class="progress-bar progress-bar-striped progress-bar-animated" style="width: 45%"></div>
</div>

<div class="progress">
  <div class="progress-bar progress-bar-success progress-bar-striped progress-bar-animated" style="width: 70%"></div>
</div>

Progress Bar Sizes

50%
50%
<!-- Small -->
<div class="progress progress-sm">
  <div class="progress-bar" style="width: 50%"></div>
</div>

<!-- Normal -->
<div class="progress">
  <div class="progress-bar" style="width: 50%"></div>
</div>

<!-- Large -->
<div class="progress progress-lg">
  <div class="progress-bar" style="width: 50%">50%</div>
</div>

<!-- Extra Large -->
<div class="progress progress-xl">
  <div class="progress-bar" style="width: 50%">50%</div>
</div>

Multiple Progress Bars

15%
30%
20%
<div class="progress">
  <div class="progress-bar progress-bar-primary" style="width: 15%">15%</div>
  <div class="progress-bar progress-bar-success" style="width: 30%">30%</div>
  <div class="progress-bar progress-bar-info" style="width: 20%">20%</div>
</div>
Note: Use the style="width: X%" attribute to set the progress value. You can dynamically update this with JavaScript to create animated progress indicators.

Dynamic Progress Example

0%
function startProgress() {
    const progressBar = document.getElementById('dynamicProgress');
    let width = 0;
    
    const interval = setInterval(() => {
        if (width >= 100) {
            clearInterval(interval);
        } else {
            width++;
            progressBar.style.width = width + '%';
            progressBar.textContent = width + '%';
        }
    }, 20);
}

function resetProgress() {
    const progressBar = document.getElementById('dynamicProgress');
    progressBar.style.width = '0%';
    progressBar.textContent = '0%';
}

Spinners

Spinners are loading indicators that show content is being loaded or processed.

Border Spinner

Loading...
<div class="spinner-border" role="status">
  <span class="sr-only">Loading...</span>
</div>

Growing Spinner

Loading...
<div class="spinner-grow" role="status">
  <span class="sr-only">Loading...</span>
</div>

Spinner Colors

Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
<div class="spinner-border spinner-primary" role="status">
  <span class="sr-only">Loading...</span>
</div>

<div class="spinner-border spinner-secondary" role="status">
  <span class="sr-only">Loading...</span>
</div>

<div class="spinner-border spinner-success" role="status">
  <span class="sr-only">Loading...</span>
</div>

<div class="spinner-border spinner-danger" role="status">
  <span class="sr-only">Loading...</span>
</div>

<div class="spinner-border spinner-warning" role="status">
  <span class="sr-only">Loading...</span>
</div>

<div class="spinner-border spinner-info" role="status">
  <span class="sr-only">Loading...</span>
</div>

<div class="spinner-border spinner-dark" role="status">
  <span class="sr-only">Loading...</span>
</div>

Growing Spinner Colors

Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
<div class="spinner-grow spinner-primary" role="status">
  <span class="sr-only">Loading...</span>
</div>

<div class="spinner-grow spinner-secondary" role="status">
  <span class="sr-only">Loading...</span>
</div>

<div class="spinner-grow spinner-success" role="status">
  <span class="sr-only">Loading...</span>
</div>

Spinner Sizes

Loading...
Loading...
Loading...
Loading...
<!-- Small -->
<div class="spinner-border spinner-border-sm" role="status">
  <span class="sr-only">Loading...</span>
</div>

<!-- Normal -->
<div class="spinner-border" role="status">
  <span class="sr-only">Loading...</span>
</div>

<!-- Large -->
<div class="spinner-border spinner-border-lg" role="status">
  <span class="sr-only">Loading...</span>
</div>

<!-- Extra Large -->
<div class="spinner-border spinner-border-xl" role="status">
  <span class="sr-only">Loading...</span>
</div>

Growing Spinner Sizes

Loading...
Loading...
Loading...
Loading...
<!-- Small -->
<div class="spinner-grow spinner-grow-sm" role="status">
  <span class="sr-only">Loading...</span>
</div>

<!-- Normal -->
<div class="spinner-grow" role="status">
  <span class="sr-only">Loading...</span>
</div>

<!-- Large -->
<div class="spinner-grow spinner-grow-lg" role="status">
  <span class="sr-only">Loading...</span>
</div>

<!-- Extra Large -->
<div class="spinner-grow spinner-grow-xl" role="status">
  <span class="sr-only">Loading...</span>
</div>

Spinners in Buttons

<button class="btn btn-primary" disabled>
  <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
  Loading...
</button>

<button class="btn btn-success" disabled>
  <span class="spinner-grow spinner-grow-sm" role="status" aria-hidden="true"></span>
  Loading...
</button>

<button class="btn btn-secondary" disabled>
  <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
</button>
Note: Always include <span class="sr-only">Loading...</span> for accessibility. This provides context for screen readers.

Forms

Tani provides a comprehensive set of form components for creating beautiful and functional forms.

Basic Form

We'll never share your email with anyone else.
<form>
  <div class="form-group">
    <label for="exampleInputEmail1" class="form-label">Email address</label>
    <input type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp">
    <div class="form-text">We'll never share your email with anyone else.</div>
  </div>
  <div class="form-group">
    <label for="exampleInputPassword1" class="form-label">Password</label>
    <input type="password" class="form-control" id="exampleInputPassword1">
  </div>
  <div class="form-group">
    <label for="exampleSelect" class="form-label">Select Example</label>
    <select class="form-select" id="exampleSelect">
      <option selected>Open this select menu</option>
      <option value="1">One</option>
      <option value="2">Two</option>
      <option value="3">Three</option>
    </select>
  </div>
  <div class="form-check">
    <input type="checkbox" class="form-check-input" id="exampleCheck1">
    <label class="form-check-label" for="exampleCheck1">Check me out</label>
  </div>
  <button type="submit" class="btn btn-primary">Submit</button>
</form>

Form Controls

<div class="form-group">
  <label for="exampleFormControlInput1" class="form-label">Email address</label>
  <input type="email" class="form-control" id="exampleFormControlInput1" placeholder="name@example.com">
</div>
<div class="form-group">
  <label for="exampleFormControlTextarea1" class="form-label">Example textarea</label>
  <textarea class="form-control" id="exampleFormControlTextarea1" rows="3"></textarea>
</div>
<div class="form-group">
  <label for="formFile" class="form-label">Default file input example</label>
  <input class="form-control" type="file" id="formFile">
</div>

Checkboxes and Radios

<div class="form-check">
  <input class="form-check-input" type="checkbox" value="" id="flexCheckDefault">
  <label class="form-check-label" for="flexCheckDefault">
    Default checkbox
  </label>
</div>
<div class="form-check">
  <input class="form-check-input" type="checkbox" value="" id="flexCheckChecked" checked>
  <label class="form-check-label" for="flexCheckChecked">
    Checked checkbox
  </label>
</div>
<div class="form-check">
  <input class="form-check-input" type="radio" name="flexRadioDefault" id="flexRadioDefault1">
  <label class="form-check-label" for="flexRadioDefault1">
    Default radio
  </label>
</div>
<div class="form-check">
  <input class="form-check-input" type="radio" name="flexRadioDefault" id="flexRadioDefault2" checked>
  <label class="form-check-label" for="flexRadioDefault2">
    Default checked radio
  </label>
</div>

Form Grid

<form>
  <div class="form-row">
    <div class="form-col">
      <input type="text" class="form-control" placeholder="First name">
    </div>
    <div class="form-col">
      <input type="text" class="form-control" placeholder="Last name">
    </div>
  </div>
</form>

Sizing



<input class="form-control form-control-lg" type="text" placeholder="Large input">
<input class="form-control" type="text" placeholder="Default input">
<input class="form-control form-control-sm" type="text" placeholder="Small input">

Pagination

Pagination components for navigating through pages of content.

Basic Pagination

<nav>
  <ul class="pagination">
    <li class="page-item">
      <a class="page-link" href="#">Previous</a>
    </li>
    <li class="page-item">
      <a class="page-link" href="#">1</a>
    </li>
    <li class="page-item active">
      <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</a>
    </li>
  </ul>
</nav>

Pagination with Icons

<nav>
  <ul class="pagination">
    <li class="page-item">
      <a class="page-link" href="#">ยซ</a>
    </li>
    <li class="page-item">
      <a class="page-link" href="#">1</a>
    </li>
    <li class="page-item">
      <a class="page-link" href="#">2</a>
    </li>
    <li class="page-item active">
      <a class="page-link" href="#">3</a>
    </li>
    <li class="page-item">
      <a class="page-link" href="#">4</a>
    </li>
    <li class="page-item">
      <a class="page-link" href="#">5</a>
    </li>
    <li class="page-item">
      <a class="page-link" href="#">ยป</a>
    </li>
  </ul>
</nav>

Disabled and Active States

<nav>
  <ul class="pagination">
    <li class="page-item disabled">
      <a class="page-link" href="#">Previous</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</a>
    </li>
  </ul>
</nav>

Pagination Sizes

<!-- Small -->
<nav>
  <ul class="pagination pagination-sm">
    <li class="page-item">
      <a class="page-link" href="#">ยซ</a>
    </li>
    <li class="page-item">
      <a class="page-link" href="#">1</a>
    </li>
    <li class="page-item active">
      <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="#">ยป</a>
    </li>
  </ul>
</nav>

<!-- Normal -->
<nav>
  <ul class="pagination">
    ...
  </ul>
</nav>

<!-- Large -->
<nav>
  <ul class="pagination pagination-lg">
    ...
  </ul>
</nav>

Pagination Alignment

<!-- Left aligned (default) -->
<nav>
  <ul class="pagination">
    ...
  </ul>
</nav>

<!-- Center aligned -->
<nav>
  <ul class="pagination pagination-center">
    ...
  </ul>
</nav>

<!-- Right aligned -->
<nav>
  <ul class="pagination pagination-end">
    ...
  </ul>
</nav>

Rounded Pagination

<nav>
  <ul class="pagination pagination-rounded">
    <li class="page-item">
      <a class="page-link" href="#">ยซ</a>
    </li>
    <li class="page-item">
      <a class="page-link" href="#">1</a>
    </li>
    <li class="page-item">
      <a class="page-link" href="#">2</a>
    </li>
    <li class="page-item active">
      <a class="page-link" href="#">3</a>
    </li>
    <li class="page-item">
      <a class="page-link" href="#">4</a>
    </li>
    <li class="page-item">
      <a class="page-link" href="#">5</a>
    </li>
    <li class="page-item">
      <a class="page-link" href="#">ยป</a>
    </li>
  </ul>
</nav>
Note: Use the active class on .page-item to indicate the current page, and disabled class to disable navigation links.

Accordion

Accordions allow users to toggle the display of sections of content.

Basic Accordion

This is the first item's accordion body. It is shown by default.

This is the second item's accordion body. It is hidden by default.

This is the third item's accordion body. It is hidden by default.
<div class="accordion" id="accordionBasic">
  <div class="accordion-item">
    <h2 class="accordion-header">
      <button class="accordion-button" type="button" data-accordion="collapseOne">
        Accordion Item #1
      </button>
    </h2>
    <div id="collapseOne" class="accordion-collapse show">
      <div class="accordion-body">
        This is the first item's accordion body.
      </div>
    </div>
  </div>
  <div class="accordion-item">
    <h2 class="accordion-header">
      <button class="accordion-button collapsed" type="button" data-accordion="collapseTwo">
        Accordion Item #2
      </button>
    </h2>
    <div id="collapseTwo" class="accordion-collapse">
      <div class="accordion-body">
        This is the second item's accordion body.
      </div>
    </div>
  </div>
</div>

Flush Accordion

Flush accordion removes borders and rounded corners.

Perfect for sidebars or minimal designs.
<div class="accordion accordion-flush">
  <div class="accordion-item">
    <h2 class="accordion-header">
      <button class="accordion-button collapsed" type="button" data-accordion="flushOne">
        Flush Item #1
      </button>
    </h2>
    <div id="flushOne" class="accordion-collapse">
      <div class="accordion-body">
        Flush accordion removes borders and rounded corners.
      </div>
    </div>
  </div>
</div>

Bordered Accordion

Each item has its own border and spacing.

Great for card-like appearance.
<div class="accordion accordion-bordered">
  <div class="accordion-item">
    <h2 class="accordion-header">
      <button class="accordion-button collapsed" type="button" data-accordion="borderedOne">
        Bordered Item #1
      </button>
    </h2>
    <div id="borderedOne" class="accordion-collapse">
      <div class="accordion-body">
        Each item has its own border and spacing.
      </div>
    </div>
  </div>
</div>

Accordion with Icons

Accordion with plus/minus icon indicators.

The icon rotates when expanded.
<div class="accordion accordion-icon">
  <div class="accordion-item">
    <h2 class="accordion-header">
      <button class="accordion-button collapsed" type="button" data-accordion="iconOne">
        Icon Item #1
      </button>
    </h2>
    <div id="iconOne" class="accordion-collapse">
      <div class="accordion-body">
        Accordion with plus/minus icon indicators.
      </div>
    </div>
  </div>
</div>

Colored Accordions

Active header has primary color background.

Active header has secondary color background.

Active header has success color background.

Active header has dark color background.
<!-- Primary -->
<div class="accordion accordion-primary">...</div>

<!-- Secondary -->
<div class="accordion accordion-secondary">...</div>

<!-- Success -->
<div class="accordion accordion-success">...</div>

<!-- Dark -->
<div class="accordion accordion-dark">...</div>

Accordion with Shadow

Accordion with elevated shadow effect.

Adds depth to the accordion.
<div class="accordion accordion-shadow">
  <div class="accordion-item">
    <h2 class="accordion-header">
      <button class="accordion-button collapsed" type="button" data-accordion="shadowOne">
        Shadow Item #1
      </button>
    </h2>
    <div id="shadowOne" class="accordion-collapse">
      <div class="accordion-body">
        Accordion with elevated shadow effect.
      </div>
    </div>
  </div>
</div>

Combined Styles

Primary + Bordered + Shadow combined together.

Mix and match different styles for unique designs.
<div class="accordion accordion-primary accordion-bordered accordion-shadow">
  <div class="accordion-item">
    <h2 class="accordion-header">
      <button class="accordion-button collapsed" type="button" data-accordion="combinedOne">
        Combined Styles
      </button>
    </h2>
    <div id="combinedOne" class="accordion-collapse">
      <div class="accordion-body">
        Primary + Bordered + Shadow combined together.
      </div>
    </div>
  </div>
</div>

JavaScript

Accordions require JavaScript to toggle content. Here's the complete code:

// Accordion functionality
document.addEventListener('DOMContentLoaded', function() {
    const accordionButtons = document.querySelectorAll('[data-accordion]');
    
    accordionButtons.forEach(button => {
        button.addEventListener('click', function() {
            const targetId = this.getAttribute('data-accordion');
            const target = document.getElementById(targetId);
            const accordion = this.closest('.accordion');
            
            if (!target) return;
            
            // Check if we should close others (default behavior)
            const closeOthers = !accordion.hasAttribute('data-allow-multiple');
            
            if (closeOthers) {
                // Close all other items in this accordion
                accordion.querySelectorAll('.accordion-collapse.show').forEach(collapse => {
                    if (collapse !== target) {
                        collapse.classList.remove('show');
                        const btn = accordion.querySelector(`[data-accordion="${collapse.id}"]`);
                        if (btn) btn.classList.add('collapsed');
                    }
                });
            }
            
            // Toggle current item
            target.classList.toggle('show');
            this.classList.toggle('collapsed');
        });
    });
});
Tip: Add data-allow-multiple attribute to the accordion container to allow multiple items to be open at once.
Note: By default, only one accordion item can be open at a time. The open item will automatically close when another is opened.

Utility Classes

Tani provides a comprehensive set of utility classes for common styling needs.

Spacing Utilities

Margin and padding utilities use a 5-level scale (0-5):

Size Value Example
0 0 .m-0, .p-0
1 0.25rem .m-1, .p-1
2 0.5rem .m-2, .p-2
3 1rem .m-3, .p-3
4 1.5rem .m-4, .p-4
5 3rem .m-5, .p-5
Tip: Use directional prefixes for specific sides: t (top), r (right), b (bottom), l (left), x (horizontal), y (vertical).

Display Utilities

Class Property
.d-none display: none;
.d-inline display: inline;
.d-inline-block display: inline-block;
.d-block display: block;
.d-flex display: flex;

Flexbox Utilities

Class Property
.d-flex display: flex;
.flex-row flex-direction: row;
.flex-column flex-direction: column;
.justify-content-start justify-content: flex-start;
.justify-content-center justify-content: center;
.justify-content-between justify-content: space-between;
.align-items-start align-items: flex-start;
.align-items-center align-items: center;

Text Utilities

Class Property
.text-left text-align: left;
.text-center text-align: center;
.text-right text-align: right;
.text-muted color: #6c757d;
.text-primary color: var(--primary);

Border Radius Utilities

Class Property
.rounded-0 border-radius: 0 !important;
.rounded-1 border-radius: 5px !important;
.rounded-2 border-radius: 10px !important;
.rounded-3 border-radius: 15px !important;
.rounded-4 border-radius: 20px !important;
.rounded-5 border-radius: 25px !important;

Font Size Utilities

Class Property
.fs-1 font-size: 1.5rem !important;
.fs-2 font-size: 1.25rem !important;
.fs-3 font-size: 1.12rem !important;
.fs-4 font-size: 0.87rem !important;
.fs-5 font-size: 0.75rem !important;

Font Weight Utilities

Class Property
.font-bold font-weight: bold !important;
.font-normal font-weight: normal !important;

Shadow Utilities

Class Property
.shadow-sm box-shadow: var(--shadow-sm) !important;
.shadow box-shadow: var(--box-shadow) !important;
.shadow-lg box-shadow: var(--shadow-lg) !important;
.shadow-none box-shadow: none !important;

Typography

Tani provides a consistent typography system with headings, paragraphs, and lists.

Headings

h1. Heading

h2. Heading

h3. Heading

h4. Heading

h5. Heading
h6. Heading

                            <h1>h1. Heading</h1>
                            <h2>h2. Heading</h2>
                            <h3>h3. Heading</h3>
                            <h4>h4. Heading</h4>
                            <h5>h5. Heading</h5>
                            <h6>h6. Heading</h6>
                            

Paragraphs

This is a paragraph with default styling. It has appropriate line height and margins for readability.

This is a muted paragraph using the .text-muted class.


                            <p>This is a paragraph with default styling.</p>
                            <p class="text-muted">This is a muted paragraph...</p>