Skip to Content
TemplatesJavaScript

JavaScript

Flute CMS uses JavaScript for interactivity. Main libraries: HTMX, jQuery, Notyf.

Including Scripts

In the Theme

Create assets/scripts/app.js — it is automatically included in the layout:

// assets/scripts/app.js document.addEventListener('DOMContentLoaded', () => { console.log('Theme loaded'); initMyFeatures(); }); function initMyFeatures() { // your code }

On a Specific Page

@push('scripts') <script> document.addEventListener('DOMContentLoaded', () => { // code for this page }); </script> @endpush

External Module File

@push('scripts') @at('Modules/Shop/Resources/assets/js/cart.js') @endpush

Notifications (Notyf)

The global object notyf is available on all pages.

Basic Notifications

// Success notyf.success('Saved!'); // Error notyf.error('An error occurred');

Extended Options

notyf.open({ type: 'success', // success, error, warning, info message: 'Message', duration: 5000, // ms, 0 = do not close dismissible: true, // can be closed position: { x: 'right', // left, center, right y: 'top' // top, bottom } });

Examples

// After form submission $('form').on('submit', async function(e) { e.preventDefault(); try { await saveData(); notyf.success('Data saved'); } catch (error) { notyf.error('Error: ' + error.message); } });

Modals

Opening/Closing

// Open openModal('modal-id'); // Close closeModal('modal-id');

Via Data Attributes

{{-- Opening --}} <x-button data-modal-open="my-modal">Open</x-button> {{-- Closing from inside the modal --}} <x-button data-modal-close="my-modal">Close</x-button>

Programmatically with Content

// Open modal and load content $('#my-modal .modal-body').load('/api/content', function() { openModal('my-modal'); });

Events

// Modal opened window.addEventListener('open-modal', (e) => { console.log('Opened:', e.detail.modalId); }); // Modal closed window.addEventListener('close-modal', (e) => { console.log('Closed:', e.detail.modalId); });

Tooltips

<!-- Basic tooltip --> <button data-tooltip="Tooltip">Hover</button> <!-- With position --> <button data-tooltip="Top" data-tooltip-placement="top">Hover</button> <button data-tooltip="Bottom" data-tooltip-placement="bottom">Hover</button> <button data-tooltip="Left" data-tooltip-placement="left">Hover</button> <button data-tooltip="Right" data-tooltip-placement="right">Hover</button> <!-- HTML content via selector --> <button data-tooltip="#tooltip-html">Complex</button> <div id="tooltip-html" style="display:none"> <strong>Title</strong> <p>Description</p> </div>

Basic

{{-- Button --}} <button data-dropdown-open="user-menu"> Menu <x-icon path="ph.regular.caret-down" /> </button> {{-- Content --}} <div data-dropdown="user-menu" class="dropdown"> <a href="/profile" class="dropdown__item"> <x-icon path="ph.regular.user" /> Profile </a> <a href="/settings" class="dropdown__item"> <x-icon path="ph.regular.gear" /> Settings </a> <hr class="dropdown__divider"> <a href="/logout" class="dropdown__item dropdown__item--danger"> <x-icon path="ph.regular.sign-out" /> Logout </a> </div>

Hover Dropdown

<button data-dropdown-open="menu" data-dropdown-hover="true"> Hover </button>

Action Confirmation

HTMX Confirmation

<x-button hx-delete="/api/item/123" hx-flute-confirm="Delete this item?" hx-flute-confirm-type="error" hx-trigger="confirmed"> Delete </x-button>

Types

TypeColorUsage
errorRedDeletion
warningYellowWarning
successGreenConfirmation
infoBlueInformation
accentAccentMain

URL Helper

// Full URL u('/profile') // → https://site.com/profile u('api/users') // → https://site.com/api/users u() // → https://site.com/ // Usage example fetch(u('api/users')) .then(r => r.json()) .then(data => console.log(data));

Cookies

// Set cookie setCookie('theme', 'dark', 365); // for 365 days // Get cookie const theme = getCookie('theme'); // Delete cookie eraseCookie('theme');

Theme Switching

// Get current theme const theme = document.documentElement.getAttribute('data-theme'); // 'light' or 'dark' // Switch const newTheme = theme === 'light' ? 'dark' : 'light'; document.documentElement.setAttribute('data-theme', newTheme); setCookie('theme', newTheme, 365); // Or via event window.dispatchEvent(new CustomEvent('switch-theme', { detail: { theme: 'dark' } }));

HTMX

Flute uses HTMX for dynamic updates without page reloads.

Basic Examples

{{-- GET request --}} <button hx-get="/api/data" hx-target="#result"> Load </button> <div id="result"></div> {{-- POST request --}} <form hx-post="/api/save" hx-target="#result"> <input name="title"> <button type="submit">Save</button> </form> {{-- DELETE with confirmation --}} <button hx-delete="/api/item/1" hx-target="closest .item" hx-swap="outerHTML" hx-flute-confirm="Delete?"> Delete </button>
<a href="/page" hx-boost="true" hx-target="#main" hx-swap="outerHTML transition:true"> Link </a>

Attributes

AttributeDescription
hx-getGET request
hx-postPOST request
hx-putPUT request
hx-deleteDELETE request
hx-targetWhere to insert the result
hx-swapHow to insert (innerHTML, outerHTML, beforeend…)
hx-triggerWhen to execute (click, change, load…)
hx-boostSPA-like navigation

Re-initialization After HTMX

When loading content dynamically, JS needs to be re-initialized:

// After inserting new content htmx.on('htmx:afterSwap', (event) => { initMyComponents(); initTooltips(); initDropdowns(); }); // After any request htmx.on('htmx:afterRequest', (event) => { // update counters, badges, etc. });

Creating Your Own Module

// assets/scripts/my-module.js class MyModule { constructor() { this.init(); } init() { this.bindEvents(); } bindEvents() { // Delegation for dynamic content $(document).on('click', '.my-button', (e) => { this.handleClick(e); }); // Re-initialization after HTMX htmx.on('htmx:afterSwap', () => { this.refresh(); }); } handleClick(event) { event.preventDefault(); const $btn = $(event.currentTarget); // ... } refresh() { // re-initialization } } // Initialization $(document).ready(() => { window.myModule = new MyModule(); });

Global Objects

After page load, the following are available:

app // FluteApp instance notyf // Notyf (notifications) htmx // HTMX $ // jQuery

Useful Functions

// Wait for DOM load $(document).ready(() => { }); document.addEventListener('DOMContentLoaded', () => { }); // Event delegation (works with dynamic content) $(document).on('click', '.selector', handler); // Debounce for search let timeout; $('#search').on('input', function() { clearTimeout(timeout); timeout = setTimeout(() => { // perform search }, 300); });