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
- Folder Structure
- JavaScript Architecture
- Component System
- Loading Strategy
- 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
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
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
- No Conflicts: Namespaced under
window.ComponentName - Progressive Enhancement: Works with or without JS (content is visible)
- Library Compatible: Works alongside jQuery, Bootstrap, etc.
- Easy Debugging: Each component is self-contained
- AJAX-Friendly: Call
App.refresh(container)after dynamic content load to re-bind components
5. CSS Management (Tailwind / Bootstrap)
Option A: Tailwind CSS (Recommended)
To use Tailwind, we recommend the CLI approach watching your file changes.
- Install Tailwind via NPM:
npm install -D tailwindcss npx tailwindcss init - Configure
tailwind.config.jsto scan your PHP views:module.exports = { content: ["./src/app/Modules/**/*.{php,js}", "./src/app/Views/**/*.php"], theme: { extend: {} }, plugins: [], } - 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.
- Download Bootstrap CSS/JS or use CDN.
- Update
src/public/index.phpor 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>modal.css and button.css in favor of Bootstrap classes.