v1.0
Docs / Frontend Architecture

Frontend Architecture

The frontend architecture is designed to be modular, component-based, and progressive. It uses Vanilla JS with a lightweight orchestrator, ensuring high performance and zero build-step dependency for standard development.

Table of Contents

  1. Folder Structure
  2. JavaScript Architecture
  3. Component System
  4. Loading Strategy
  5. CSS Management (Tailwind/Bootstrap)

1. Folder Structure

All public assets are organized in public/assets/:


public/assets/
├── css/
│   ├── app.css           # Reset, typography, CSS variables, utilities
│   ├── layout.css        # Header, sidebar, footer, main content  
│   │
│   ├── components/       # Reusable UI component styles
│   │   ├── button.css    # All button variants
│   │   ├── modal.css     # Modal dialogs
│   │   ├── datatable.css # Tables and DataTables
│   │   └── form.css      # Inputs, selects, checkboxes
│   │
│   ├── pages/            # Page-specific styles
│   │   ├── admin-dashboard.css
│   │   ├── admin-users.css
│   │   └── member-profile.css
│   │
│   ├── themes/           # Theme variants
│   │   └── dark.css      # Dark mode overrides
│   │
│   └── vendor/           # Third-party CSS
│
├── js/
│   ├── app.js            # Main orchestrator (auto-inits components)
│   │
│   ├── components/       # Reusable UI components (IIFE pattern)
│   │   ├── sidebar.js    # Collapsible sidebar with persistence
│   │   ├── modal.js      # Accessible modal dialogs
│   │   ├── datatable.js  # jQuery DataTables or native fallback
│   │   ├── toast.js      # Toast notifications
│   │   ├── dropdown.js   # Click/hover dropdown menus
│   │   └── tooltip.js    # Hover tooltips
│   │
│   ├── modules/          # Page-specific JavaScript
│   │   ├── admin-dashboard.js
│   │   ├── admin-user.js
│   │   └── member-profile.js
│   │
│   └── vendor/           # Third-party JS (jQuery, Chart.js)
│
├── images/
│   └── avatars/
│
└── fonts/

2. JavaScript Architecture

Goal: Understand why we use IIFE (Immediately Invoked Function Expressions) to avoid polluting the global namespace.

IIFE Pattern (Namespaced Components)

All components use the Immediately Invoked Function Expression (IIFE) pattern to avoid global namespace pollution. Each component exposes a single global object (e.g., window.DataTableComponent).


window.DataTableComponent = (function() {
    'use strict';

    function initAll(context) {
        const ctx = context || document;
        ctx.querySelectorAll('[data-datatable]').forEach(table => {
            initFromDataset(table);
        });
    }

    function initFromDataset(table) {
        const options = {
            searching: table.dataset.searching !== 'false',
        };
        // ... initialization logic
    }

    return {
        initAll
    };
})();

Component Auto-Initialization

The app.js orchestrator automatically initializes all registered components on page load. This means you don't need to write manual initialization code for standard components.


window.App = (function() {
    function init() {
        initComponent('SidebarComponent');
        initComponent('DropdownComponent');
        initComponent('ModalComponent');
        initComponent('ToastComponent');
        initComponent('DataTableComponent');
    }

    function initComponent(name) {
        if (window[name] && typeof window[name].initAll === 'function') {
            window[name].initAll();
        }
    }

    return { init, refresh };
})();

3. Component System

Task: Add a `data-tooltip` attribute to a button and verify it shows up on hover without writing any JS.

Data Attribute API

Components are initialized entirely via HTML data-* attributes. This keeps your Views clean and declarative.

DataTable

<table data-datatable data-searching="true" data-order="0,asc">

Sidebar

<aside data-sidebar data-persist="true">

Modal

<!-- Trigger -->
<button data-modal-open="confirmDelete">Delete</button>

<!-- Content -->
<div data-modal="confirmDelete">
    ...
</div>

Tooltip

<span data-tooltip="Help text" data-placement="top">Hover me</span>

Dropdown

<div data-dropdown data-hover="true">
    <button data-dropdown-toggle>Menu</button>
    <div data-dropdown-menu>...</div>
</div>

4. Loading Strategy

Performance is critical. We follow a strict loading order to ensure dependencies are met while keeping the initial render fast.

Script Loading Order

In layout files (e.g., admin.php), scripts are loaded in this specific order:


<!-- 1. Vendor scripts (Only if absolutely needed) -->
<script src="/assets/js/vendor/jquery.min.js"></script>

<!-- 2. Core orchestrator -->
<script src="/assets/js/app.js"></script>

<!-- 3. UI Components (Shared library) -->
<script src="/assets/js/components/sidebar.js"></script>
<script src="/assets/js/components/modal.js"></script>
<script src="/assets/js/components/datatable.js"></script>

<!-- 4. Page-specific modules (Lazy loaded or conditional) -->
<script src="/assets/js/modules/admin-dashboard.js"></script>

Benefits


5. CSS Management (Tailwind / Bootstrap)

Goal: Integrate modern CSS frameworks without breaking the modular architecture.

Option A: Tailwind CSS (Recommended)

To use Tailwind, we recommend the CLI approach watching your file changes.

  1. Install Tailwind via NPM:
    npm install -D tailwindcss
    npx tailwindcss init
  2. Configure tailwind.config.js to scan your PHP views:
    module.exports = {
      content: ["./src/app/Modules/**/*.{php,js}", "./src/app/Views/**/*.php"],
      theme: { extend: {} },
      plugins: [],
    }
  3. Run the watcher during development:
    npx tailwindcss -i ./src/public/assets/css/input.css -o ./src/public/assets/css/app.css --watch

Option B: Bootstrap 5

For Bootstrap, you can simply include the CDN or local file in your main layout.

  1. Download Bootstrap CSS/JS or use CDN.
  2. Update src/public/index.php or your main layout file:
<!-- In <head> -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">

<!-- At bottom of <body> -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
Note: If using Bootstrap, you may typically skip our custom modal.css and button.css in favor of Bootstrap classes.
ESC

Start typing to search the documentation