MenoFilter API Reference
MenoFilter is a client-side JavaScript library for filtering, sorting, searching, and paginating CMS collection data on static websites. It works with both data attributes (declarative) and a programmatic JavaScript API.
Getting an Instance
MenoFilter instances are registered by collection name. Instances are created automatically when the page loads (from data-meno-filter containers) or can be created programmatically.
// Get an existing instance
const filter = MenoFilter.get('posts');
// Create a new instance
const filter = new MenoFilter({
collection: 'posts',
perPage: 10,
filterMatch: 'and'
});
// Initialize (loads data from inline JSON or static file)
await filter.init();Constructor Options
Option | Type | Default | Description | |
|---|---|---|---|---|
|
| (required) | Collection name | |
|
|
| Items per page | |
| `"and" \ | "or"` |
| How multiple filter fields combine |
|
|
| Type hints for value coercion | |
|
|
| Sync filter state to URL query params | |
| `"push" \ | "replace"` |
| URL update mode ( |
|
|
| Enable fuzzy text matching | |
|
|
| Fuzzy match threshold (0-1, lower is stricter) |
Static Methods
Method | Returns | Description | |
|---|---|---|---|
| `MenoFilter \ | undefined` | Get instance by collection name |
|
| Get all registered instances | |
|
| Check if an instance exists | |
|
| Destroy and unregister an instance | |
|
| Destroy all instances |
Filtering Methods
Method | Returns | Description |
|---|---|---|
|
| Apply filter criteria (AND logic between fields) |
|
| Apply OR logic between criteria objects |
|
| Add/update a single filter (merges with existing) |
|
| Remove filter for a specific field |
|
| Clear all filters (keeps sort and search) |
|
| Get current filter criteria |
|
| Apply a range filter (uses |
|
| Clear a range filter |
Filter Examples
Simple equality:
filter.filter({ category: 'tech' });Multiple conditions (AND):
filter.filter({
category: 'tech',
published: true
});With operators:
filter.filter({
price: { $gt: 100, $lt: 500 },
tags: { $contains: 'featured' }
});OR filtering:
filter.filterOr([
{ category: 'tech' },
{ category: 'design' }
]);Range filter:
filter.filterRange('price', { min: 100, max: 500 });
filter.filterRange('date', { min: '2024-01-01' });Filter Operators
Operator | Description | Value Type | |
|---|---|---|---|
| Equal to |
| |
| Not equal to |
| |
| Greater than | `number \ | string` |
| Greater than or equal | `number \ | string` |
| Less than | `number \ | string` |
| Less than or equal | `number \ | string` |
| String contains (case-insensitive) or array includes |
| |
| String does not contain or array excludes |
| |
| String starts with (case-insensitive) |
| |
| String ends with (case-insensitive) |
| |
| Value is in the given array |
| |
| Value is not in the given array |
| |
| Is empty/null ( |
|
A filter value of "*", "", null, or undefined is treated as "show all" and skipped.
Search Methods
Method | Returns | Description |
|---|---|---|
|
| Search text across fields (case-insensitive) |
|
| Clear search query |
|
| Get current search state |
|
| Enable/disable fuzzy matching |
|
| Check if fuzzy search is on |
// Search all string fields
filter.search('react tutorial');
// Search specific fields only
filter.search('react', ['title', 'tags']);
// Enable fuzzy matching
filter.setFuzzySearch(true, 0.3);
filter.search('reckt'); // matches "react" with typo toleranceSort Methods
Method | Returns | Description | |
|---|---|---|---|
|
| Sort by field ( | |
|
| Clear sorting | |
| `SortConfig \ | null` | Get current sort configuration |
filter.sort('publishedAt', 'desc');
filter.sort('title', 'asc');
filter.clearSort();Pagination Methods
Method | Returns | Description |
|---|---|---|
|
| Go to page number |
|
| Go to next page |
|
| Go to previous page |
|
| Set items per page |
|
| Get pagination state |
PageInfo Object
Field | Type | Description |
|---|---|---|
|
| Current page number (1-based) |
|
| Total number of pages |
|
| Whether there is a next page |
|
| Whether there is a previous page |
|
| Total filtered item count |
|
| Items per page |
filter.setPerPage(12);
filter.setPage(2);
const info = filter.getPageInfo();
// { current: 2, total: 5, hasNext: true, hasPrev: true, totalItems: 58, perPage: 12 }Load More Methods
An alternative to pagination where items are appended incrementally.
Method | Returns | Description |
|---|---|---|
|
| Load more items (defaults to |
|
| Get currently visible items |
|
| Get load-more state |
|
| Initialize load-more mode |
LoadMoreInfo Object
Field | Type | Description |
|---|---|---|
|
| Number of currently visible items |
|
| Total filtered item count |
|
| Items not yet shown |
|
| Whether more items can be loaded |
filter.initLoadMore(6);
filter.loadMore(); // shows 6 more
filter.loadMore(3); // shows 3 more
const info = filter.getLoadMoreInfo();
// { visible: 15, total: 50, remaining: 35, hasMore: true }Data Access Methods
Method | Returns | Description | |
|---|---|---|---|
|
| All items (unfiltered, unsorted) | |
|
| Filtered items (before pagination) | |
|
| Current page items | |
| `CMSItem \ | undefined` | Find item by |
|
| All unique values for a field | |
|
| Value counts from filtered items | |
|
| Value counts from all items | |
|
| Full state snapshot |
const allItems = filter.getAll();
const filtered = filter.getFiltered();
const pageItems = filter.getItems();
const categories = filter.getUniqueValues('category');
// ['tech', 'design', 'marketing']
const facets = filter.getFacets('category');
// { tech: 12, design: 8, marketing: 3 }Reset
Method | Returns | Description |
|---|---|---|
|
| Reset all filters, search, sort, and pagination |
Events
Subscribe to lifecycle events using on(). Returns an unsubscribe function.
const unsubscribe = filter.on('afterFilter', (items) => {
console.log('Filtered to', items.length, 'items');
});
// Later: unsubscribe
unsubscribe();Event Types
Event | Callback Data | Description |
|---|---|---|
|
| Fired after data is loaded |
|
| Before filter criteria are applied |
|
| After filtering completes |
|
| Before sort is applied |
|
| After sorting completes |
|
| Before search is applied |
|
| After search completes |
| varies | Before DOM render |
| varies | After DOM render |
|
| When page changes |
|
| When more items are loaded |
|
| When reset() is called |
Watch and Subscribe
// Watch full state changes
const unwatch = filter.watch((state) => {
console.log(state.pageItems.length, 'items on page', state.page.current);
});
// Subscribe to items only (simplified)
const unsub = filter.subscribe((items) => {
console.log(items.length, 'current items');
});URL Sync
Synchronize filter state with URL query parameters so users can share filtered views.
filter.enableUrlSync({ mode: 'push' }); // adds browser history entries
filter.enableUrlSync(); // replaces URL without history
filter.disableUrlSync();URL parameter format:
Filters:
?filter.category=tech&filter.price.$gt=100Sort:
?sort=publishedAt:descSearch:
?search=react&search.fields=title,tagsPage:
?page=2&perPage=12
Data Attributes Reference
Use these HTML attributes for declarative (no-code) filtering.
Container Attributes
Attribute | Description | |
|---|---|---|
| Root filter container. Value is the collection name. | |
| Marks the element containing list items | |
| Items per page | |
`data-meno-filter-match="and\ | or"` | How multiple filters combine |
| Debounce delay for inputs | |
| Class added to active filter buttons | |
| JSON object of field type hints | |
| Enable URL query parameter sync |
Filter Controls
Attribute | Description | |
|---|---|---|
| Field name this control filters on | |
| Value to filter by (on buttons/links) | |
`data-meno-filter-mode="single\ | multi"` | Single or multi-select mode |
| Clears all filters when clicked | |
| Resets all state (filters, sort, search, page) |
Range Controls
Attribute | Description | |
|---|---|---|
| Marks a range filter container | |
`data-meno-range-bound="min\ | max"` | Marks an input as min or max bound |
Search Controls
Attribute | Description |
|---|---|
| Marks a search input |
| Comma-separated fields to search |
| Enable fuzzy matching |
| Fuzzy match threshold |
Sort Controls
Attribute | Description | |
|---|---|---|
| Sort by this field when clicked | |
`data-meno-sort-order="asc\ | desc"` | Sort direction |
Pagination Controls
Attribute | Description | ||
|---|---|---|---|
`data-meno-page="prev\ | next\ | n"` | Page navigation button |
| Displays the current page number | ||
| Displays the total page count | ||
| Container for auto-generated page buttons | ||
| Select/input to change items per page |
Load More Controls
Attribute | Description |
|---|---|
| "Load more" button |
| Displays the remaining item count |
Display Elements
Attribute | Description | |
|---|---|---|
`data-meno-count="results\ | total"` | Shows filtered or total item count |
| Shows facet counts for a field | |
| Shown when no items match filters |
Declarative Example
<div data-meno-filter="posts" data-meno-per-page="6">
<!-- Search -->
<input data-meno-search data-meno-search-fields="title,excerpt" placeholder="Search...">
<!-- Filter buttons -->
<button data-meno-filter-field="category" data-meno-filter-value="*">All</button>
<button data-meno-filter-field="category" data-meno-filter-value="tech">Tech</button>
<button data-meno-filter-field="category" data-meno-filter-value="design">Design</button>
<!-- Sort -->
<button data-meno-sort="publishedAt" data-meno-sort-order="desc">Newest</button>
<button data-meno-sort="title" data-meno-sort-order="asc">A-Z</button>
<!-- Results count -->
<span data-meno-count="results"></span> results
<!-- Item list -->
<div data-meno-list>
<!-- Items are rendered here -->
</div>
<!-- Empty state -->
<div data-meno-empty>No posts found.</div>
<!-- Pagination -->
<button data-meno-page="prev">Previous</button>
<span data-meno-page-current></span> / <span data-meno-page-total></span>
<button data-meno-page="next">Next</button>
</div>Next Steps
CMS Fields -- field types and schema configuration
Node Types -- list node for server-side collection rendering
Template Expressions -- item template syntax
Project Config -- client data configuration