Isotope Extension
The Isotope extension provides responsive grid layouts with filtering capabilities using isotope-layout and imagesloaded.
Features
- Responsive Grid Layouts: Automatic item arrangement and resizing
- Filtering System: Interactive filters with active state management
- Image Loading Support: Integration with imagesloaded for proper layout timing
- Hash-based Navigation: URL hash support for filter states
- Lazy Loading Integration: Works with lazysizes for optimal performance
- Dynamic Content: Support for asynchronously loaded content
Configuration
ts
export interface IsotopeExtensionOptions {
/**
* The Isotope wrapper element. Defaults to .isotope-wrapper
*/
wrapper?: HTMLElement;
}Usage
ts
import { RunThemeExtensions } from 'wly-statamic-theme-extensions';
RunThemeExtensions({
isotope: {
wrapper: document.querySelector('#my-grid') // Optional: specific element
}
});HTML Structure
Basic Grid Layout
html
<div class="isotope-wrapper">
<div class="isotope-grid">
<div class="isotope-item category-foo">Item 1</div>
<div class="isotope-item category-bar">Item 2</div>
<div class="isotope-item category-baz">Item 3</div>
<div class="isotope-item category-foo category-bar">Item 4</div>
</div>
</div>Grid with Filters
html
<div class="isotope-wrapper">
<!-- Filter controls -->
<div class="isotope-filters">
<button data-filter="*" class="active">All</button>
<button data-filter=".category-foo">Category Foo</button>
<button data-filter=".category-bar">Category Bar</button>
<button data-filter=".category-baz">Category Baz</button>
</div>
<!-- Grid container -->
<div class="isotope-grid">
<div class="isotope-item category-foo">
<h3>Foo Item 1</h3>
<p>Content for foo category</p>
</div>
<div class="isotope-item category-bar">
<h3>Bar Item 1</h3>
<p>Content for bar category</p>
</div>
<div class="isotope-item category-baz">
<h3>Baz Item 1</h3>
<p>Content for baz category</p>
</div>
<div class="isotope-item category-foo category-bar">
<h3>Multi-category Item</h3>
<p>This item belongs to multiple categories</p>
</div>
</div>
</div>Hash-based Navigation
Create linkable filters using href attributes:
html
<div class="isotope-filters">
<a href="#all" data-filter="*" class="active">All</a>
<a href="#portfolio" data-filter=".portfolio">Portfolio</a>
<a href="#blog" data-filter=".blog">Blog</a>
<a href="#news" data-filter=".news">News</a>
</div>Features:
- URLs update when filters are clicked (
example.com/#portfolio) - Direct navigation to filtered views via URL
- Browser back/forward button support
- Hash-based initial filter on page load
Advanced Features
Dynamic Content Loading
For content loaded via AJAX or Vue components:
html
<div class="isotope-wrapper" data-change-listener="#content-trigger">
<div class="isotope-grid">
<!-- Initial content -->
</div>
</div>
<!-- Trigger element that fires 'change' event -->
<div id="content-trigger"></div>js
// After loading new content
document.getElementById('content-trigger').dispatchEvent(new Event('change'));Async Initialization
For Vue components or other async content:
html
<div class="isotope-wrapper" data-init-message="grid-ready">
<div class="isotope-grid">
<!-- Content loaded by Vue component -->
</div>
</div>js
// From Vue component or async loader
window.postMessage('grid-ready', '*');No-Filter Grid
Use isotope without filters for pure masonry layout:
html
<div class="isotope-wrapper">
<!-- No .isotope-grid needed - wrapper becomes grid -->
<div class="isotope-item">Item 1</div>
<div class="isotope-item">Item 2</div>
<div class="isotope-item">Item 3</div>
</div>CSS Integration
Basic CSS structure for responsive grid:
css
.isotope-wrapper {
width: 100%;
}
.isotope-grid {
display: flex;
flex-wrap: wrap;
}
.isotope-item {
width: 33.333%;
padding: 10px;
box-sizing: border-box;
}
@media (max-width: 768px) {
.isotope-item {
width: 50%;
}
}
@media (max-width: 480px) {
.isotope-item {
width: 100%;
}
}
.isotope-filters button.active {
background: #007cba;
color: white;
}Filter States
The extension automatically manages filter states:
- Active Class: Applied to currently selected filter
- History Management: Updates browser URL for hash-based filters
- Initial State: Detects hash on page load or falls back to active filter
- Event Handling: Click events with preventDefault and custom logic
Image Loading Integration
The extension integrates with imagesloaded to ensure proper layout:
- Automatic Detection: Waits for images to load before arranging
- Lazy Loading Support: Listens for 'lazyloaded' events
- Layout Refresh: Triggers layout updates when images load
- Dynamic Insertion: Handles new items with image content
Performance Considerations
- Debounced Events: Filter changes are debounced for smooth performance
- Opacity Animation: New items fade in with opacity transitions
- Efficient Selectors: Uses specific selectors to minimize DOM queries
- Event Delegation: Efficient event handling for multiple filters
Integration with Other Extensions
Works seamlessly with other theme extensions:
- Lazy Loading: Automatic integration with lazysizes extension
- Vue Components: Support for Vue-based content loading
- Image Optimization: Works with any image loading strategy