Load More
Total CMS provides “load more” helpers that render the first page of results server-side, then fetch subsequent pages via API as the user scrolls or clicks a button.
Requirements
Section titled “Requirements”- Edition: Standard edition or higher (requires templates feature)
- Template file: A Twig template that renders a single item (receives an
{{ object }}variable) - HTMX: Include the HTMX script in your page or load from a CDN
<script src="{{ cms.api }}/assets/htmx.min.js?v={{ cms.version }}"></script>Collection Load More
Section titled “Collection Load More”Use cms.render.loadMore() to paginate objects from a collection:
{{ cms.render.loadMore('blog', { template: 'blog/card.twig', limit: 10}) }}This renders the first 10 blog objects using blog/card.twig, then appends an HTMX trigger that automatically fetches the next page when needed.
DataView Load More
Section titled “DataView Load More”Use cms.render.loadMoreDataView() to paginate results from a saved DataView:
{{ cms.render.loadMoreDataView('recent-posts', { template: 'blog/card.twig', limit: 10}) }}Works identically to the collection version but queries a DataView by its ID.
Options Reference
Section titled “Options Reference”| Option | Type | Default | Description |
|---|---|---|---|
template | string | required | Twig template file for rendering each item. Receives {{ object }} |
limit | int | 20 | Number of items per page |
sort | string | — | Sort field (e.g., date, -date for descending) |
include | string | — | Include filter (e.g., published:true,featured:true) |
exclude | string | — | Exclude filter (e.g., draft:true) |
search | string | — | Search query string |
trigger | string | 'revealed' | HTMX trigger mode: revealed or click |
label | string | 'Load More' | Button label (only used when trigger is click) |
class | string | — | Additional CSS class for the trigger element |
transition | bool | false | Enable HTMX view transitions |
Trigger Modes
Section titled “Trigger Modes”Infinite Scroll (revealed)
Section titled “Infinite Scroll (revealed)”The default mode. A hidden <div> is placed after the rendered items. When it scrolls into view, HTMX automatically fetches the next page.
{{ cms.render.loadMore('blog', { template: 'blog/card.twig', trigger: 'revealed'}) }}Load More Button (click)
Section titled “Load More Button (click)”Renders a <button> that the user clicks to load additional items.
{{ cms.render.loadMore('blog', { template: 'blog/card.twig', trigger: 'click', label: 'Show More Posts'}) }}How It Works
Section titled “How It Works”- Initial render: The first page of items is rendered server-side into the page HTML
- HTMX trigger: After the last item, a trigger element is injected (a
<div>for infinite scroll or a<button>for click) - API request: When triggered, HTMX sends a GET request to the query endpoint with
offsetandlimitparameters - Response: The server returns the next batch of rendered HTML plus a new trigger element for the following page
- Swap: HTMX swaps the trigger element with the new content (items + next trigger) using
outerHTML - Chain continues: This repeats until no more items remain, at which point no trigger is returned
Template Files
Section titled “Template Files”Create a Twig template that renders a single item. The template receives the current object as {{ object }}:
{# templates/blog/card.twig #}<article class="blog-card"> <h2><a href="{{ cms.collection.objectUrl('blog', object.id) }}">{{ object.title }}</a></h2> <time>{{ object.date }}</time> <p>{{ object.excerpt }}</p></article>The same template is used for both the initial server render and all subsequent HTMX-loaded pages.
Styling
Section titled “Styling”The trigger element uses the cms-load-more CSS class, which you can target for custom styling:
.cms-load-more { text-align: center; padding: 2rem 0;}
/* Style the load more button */button.cms-load-more { background: #333; color: #fff; padding: 0.75rem 2rem; border: none; border-radius: 4px; cursor: pointer;}Examples
Section titled “Examples”Blog with Infinite Scroll
Section titled “Blog with Infinite Scroll”<div class="blog-feed"> {{ cms.render.loadMore('blog', { template: 'blog/card.twig', limit: 12, sort: '-date', include: 'published:true', exclude: 'draft:true' }) }}</div>Product Grid with Button
Section titled “Product Grid with Button”<div class="product-grid"> {{ cms.render.loadMore('products', { template: 'products/tile.twig', limit: 24, trigger: 'click', label: 'Load More Products', include: 'instock:true' }) }}</div>DataView Dashboard
Section titled “DataView Dashboard”<div class="recent-activity"> <h2>Recent Activity</h2> {{ cms.render.loadMoreDataView('recent-activity', { template: 'dashboard/activity-row.twig', limit: 20, trigger: 'revealed' }) }}</div>See Also
Section titled “See Also”- Index Filtering — Include/exclude filter syntax
- Total CMS Twig Adapter — Full
cmsvariable reference - Pagination — Traditional page-based pagination