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>
@endpushExternal Module File
@push('scripts')
@at('Modules/Shop/Resources/assets/js/cart.js')
@endpushNotifications (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>Dropdown Menu
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
| Type | Color | Usage |
|---|---|---|
error | Red | Deletion |
warning | Yellow | Warning |
success | Green | Confirmation |
info | Blue | Information |
accent | Accent | Main |
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>Navigation Without Reload
<a href="/page" hx-boost="true" hx-target="#main" hx-swap="outerHTML transition:true">
Link
</a>Attributes
| Attribute | Description |
|---|---|
hx-get | GET request |
hx-post | POST request |
hx-put | PUT request |
hx-delete | DELETE request |
hx-target | Where to insert the result |
hx-swap | How to insert (innerHTML, outerHTML, beforeend…) |
hx-trigger | When to execute (click, change, load…) |
hx-boost | SPA-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
$ // jQueryUseful 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);
});