Collections & Pagination
Load server-side data with search, filtering, and pagination
Collection attributes connect your HTML to server-side data collections. They enable features like pagination, search, and server-side filtering.
dbind_collection
Purpose: Load data from a named DBindly collection. This connects your HTML to server-side data.
Syntax:
<element dbind_collection="collectionName">
<!-- Child elements can access collection data -->
</element>Finding Your Collection Slug
The collectionName is the slug of your collection from the DBIndly dashboard:
- Open Dashboard → Collections
- Click on your collection
- Find the Slug in collection settings
Examples:
- Collection named "Products" → slug:
products - Collection named "Blog Posts" → slug:
blog-posts - Collection named "Team Members" → slug:
team-members
<!-- Use the slug, not the display name -->
<div dbind_collection="team-members">
...
</div>How It Works
- DBindly fetches data from the collection via your API
- Data is loaded into the element's scope
- Child elements can use
dbind_repeatand other bindings - Real-time updates are pushed automatically (if enabled)
Basic Usage
<!-- Load products collection -->
<div dbind_collection="products">
<div dbind_repeat="data">
<h3 dbind_data="name"></h3>
<p dbind_data="description"></p>
<span dbind_data="price" dbind_format="currency:USD"></span>
</div>
</div>This fetches data from your "products" collection and renders each item.
Collection Response Format
DBindly expects collections to return data in this format:
{
"data": [...], // Array of items
"total": 100, // Total item count
"page": 1, // Current page
"pageSize": 20, // Items per page
"totalPages": 5 // Total number of pages
}Use Cases
1. Product Catalog
<section class="catalog" dbind_collection="products">
<h2>Our Products</h2>
<div class="product-grid" dbind_repeat="data">
<article class="product-card">
<img dbind_src="image" dbind_alt="name">
<h3 dbind_data="name"></h3>
<p dbind_data="price" dbind_format="currency:USD"></p>
</article>
</div>
</section>2. Blog Posts
<main class="blog" dbind_collection="posts">
<article dbind_repeat="data" class="post">
<img dbind_src="featuredImage" dbind_alt="title" class="post-image">
<h2 dbind_data="title"></h2>
<div class="meta">
<span dbind_data="author.name"></span>
<time dbind_data="publishedAt" dbind_format="date:medium"></time>
</div>
<p dbind_data="excerpt"></p>
<a dbind_href="url">Read More</a>
</article>
</main>3. Team Directory
<div class="team-directory" dbind_collection="team">
<div dbind_repeat="data" class="team-member">
<img dbind_src="photo" dbind_alt="name" class="avatar">
<h4 dbind_data="name"></h4>
<span class="title" dbind_data="jobTitle"></span>
<span class="department" dbind_data="department"></span>
</div>
</div>Loading States
Use dbind_loading and dbind_skeleton for loading feedback:
<div dbind_collection="products">
<!-- Loading skeleton -->
<div dbind_loading="show" class="skeleton-grid">
<div class="skeleton-card"></div>
<div class="skeleton-card"></div>
<div class="skeleton-card"></div>
</div>
<!-- Actual content (hidden while loading) -->
<div dbind_loading="hide" class="product-grid" dbind_repeat="data">
<div class="product-card" dbind_data="name"></div>
</div>
</div>dbind_search
Purpose: Create a search input that filters collection data based on user input.
Syntax:
<input type="text" dbind_search="collectionName" placeholder="Search...">How It Works
- User types in the search input
- DBindly debounces the input (waits for typing to stop)
- A new request is made to the collection with the search query
- Results are updated in the DOM
Basic Usage
<div dbind_collection="products">
<!-- Search input -->
<input type="search" dbind_search="products" placeholder="Search products...">
<!-- Results -->
<div class="product-grid" dbind_repeat="data">
<div class="product-card">
<h3 dbind_data="name"></h3>
</div>
</div>
<!-- No results -->
<div dbind_empty="data">
<p>No products match your search.</p>
</div>
</div>Search Input Attributes
You can use standard HTML input attributes:
<input
type="search"
dbind_search="products"
placeholder="Search by name, description..."
minlength="2"
aria-label="Search products"
>Use Cases
1. Product Search with Filters
<div dbind_collection="products">
<div class="search-section">
<input type="search" dbind_search="products" placeholder="Search products...">
<select dbind_filter="products" data-field="category">
<option value="">All Categories</option>
<option value="electronics">Electronics</option>
<option value="clothing">Clothing</option>
</select>
</div>
<div class="results" dbind_repeat="data">
<div class="product" dbind_data="name"></div>
</div>
<div dbind_empty="data">
<p>No products found. Try different search terms.</p>
</div>
</div>2. User Directory Search
<div dbind_collection="users">
<div class="directory-header">
<h2>Team Directory</h2>
<input
type="search"
dbind_search="users"
placeholder="Search by name or department..."
>
</div>
<table class="user-table">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Department</th>
</tr>
</thead>
<tbody dbind_repeat="data">
<tr>
<td dbind_data="name"></td>
<td dbind_data="email"></td>
<td dbind_data="department"></td>
</tr>
</tbody>
</table>
</div>3. Instant Search with Highlight
<div dbind_collection="articles">
<input type="search" dbind_search="articles" placeholder="Search articles...">
<div dbind_repeat="data" class="search-result">
<h3 dbind_data="title"></h3>
<p dbind_html="highlightedSnippet"></p>
<a dbind_href="url">Read More</a>
</div>
</div>Debounce Behavior
DBindly automatically debounces search input to prevent excessive API calls:
- Default debounce: 300ms
- Minimum characters: 1 (configurable)
Server-Side Search
Your collection endpoint should handle the search query parameter:
GET /api/collections/products?search=headphones
The server filters data and returns matching results.
dbind_paginate
Purpose: Add automatic pagination controls to a collection.
Syntax:
<element dbind_paginate="pageSize"></element>How It Works
- Collection is loaded with the specified page size
- DBindly generates pagination controls
- Clicking a page number fetches that page of data
- The DOM updates with new results
Basic Usage
<div dbind_collection="products" dbind_paginate="12">
<!-- Products grid -->
<div class="product-grid" dbind_repeat="data">
<div class="product-card">
<h3 dbind_data="name"></h3>
</div>
</div>
<!-- Pagination controls are auto-generated -->
</div>Custom Pagination Controls
If you need custom styling, create your own pagination structure:
<div dbind_collection="products">
<div class="product-grid" dbind_repeat="data">
<div class="product-card" dbind_data="name"></div>
</div>
<!-- Custom pagination -->
<nav class="pagination" aria-label="Product pages">
<button dbind_page="prev" dbind_hide="isFirstPage">
← Previous
</button>
<span class="page-numbers" dbind_repeat="pageNumbers">
<button
dbind_page="{{number}}"
dbind_class="activeClass"
dbind_data="number"
></button>
</span>
<button dbind_page="next" dbind_hide="isLastPage">
Next →
</button>
</nav>
</div>Use Cases
1. Product Catalog with Pagination
<section class="catalog" dbind_collection="products" dbind_paginate="24">
<header class="catalog-header">
<h1>All Products</h1>
<input type="search" dbind_search="products" placeholder="Search...">
</header>
<div class="product-grid" dbind_repeat="data">
<article class="product-card">
<img dbind_src="image" dbind_alt="name">
<h3 dbind_data="name"></h3>
<p dbind_data="price" dbind_format="currency:USD"></p>
</article>
</div>
<div class="empty-state" dbind_empty="data">
<p>No products found.</p>
</div>
</section>2. Blog Archive
<div class="blog-archive" dbind_collection="posts" dbind_paginate="10">
<article dbind_repeat="data" class="post-preview">
<time dbind_data="publishedAt" dbind_format="date:long"></time>
<h2 dbind_data="title"></h2>
<p dbind_data="excerpt"></p>
<a dbind_href="url">Continue Reading →</a>
</article>
</div>dbind_loadmore
Purpose: Add a "Load More" button for infinite scroll-style pagination.
Syntax:
<button dbind_loadmore="collectionName">Load More</button>How It Works
- Initial page of data is loaded
- User clicks "Load More"
- Next page is fetched and appended to existing data
- Button hides when all data is loaded
Basic Usage
<div dbind_collection="products">
<!-- Products append here -->
<div class="product-grid" dbind_repeat="data">
<div class="product-card">
<h3 dbind_data="name"></h3>
</div>
</div>
<!-- Load more button -->
<button dbind_loadmore="products" class="btn-load-more">
Load More Products
</button>
</div>Custom Loading States
<div dbind_collection="posts">
<div dbind_repeat="data" class="post">
<h2 dbind_data="title"></h2>
</div>
<!-- Load more with states -->
<div class="load-more-container">
<button dbind_loadmore="posts" dbind_hide="isLoading">
Load More Posts
</button>
<span dbind_show="isLoading" class="loading-spinner">
Loading...
</span>
<span dbind_show="isComplete" class="all-loaded">
You've reached the end!
</span>
</div>
</div>Use Cases
1. Social Feed
<div class="social-feed" dbind_collection="posts">
<article dbind_repeat="data" class="feed-post">
<header class="post-header">
<img dbind_src="author.avatar" dbind_alt="author.name">
<span dbind_data="author.name"></span>
<time dbind_data="createdAt" dbind_format="date:relative"></time>
</header>
<p dbind_data="content"></p>
<footer class="post-actions">
<button>Like</button>
<button>Comment</button>
<button>Share</button>
</footer>
</article>
<button dbind_loadmore="posts" class="load-more">
Show More Posts
</button>
</div>2. Image Gallery
<div class="gallery" dbind_collection="images">
<div class="gallery-grid" dbind_repeat="data">
<figure class="gallery-item">
<img dbind_src="thumbnail" dbind_alt="title" loading="lazy">
<figcaption dbind_data="title"></figcaption>
</figure>
</div>
<button dbind_loadmore="images" class="btn-load-more">
Load More Images
</button>
</div>Load More vs Pagination
| Feature | dbind_paginate | dbind_loadmore |
|---|---|---|
| UI Pattern | Page numbers | "Load More" button |
| Data Display | Replace content | Append content |
| Best For | Tables, directories | Feeds, galleries |
| URL Updates | Yes (page parameter) | No |
| Browser Back | Works as expected | May lose position |
dbind_page-info
Purpose: Display pagination information like current page, total pages, and total items.
Syntax:
<element dbind_page-info="field"></element>Available Fields
| Field | Description | Example |
|---|---|---|
page | Current page number | 1 |
totalPages | Total number of pages | 10 |
total | Total number of items | 237 |
pageSize | Items per page | 20 |
from | First item number on page | 21 |
to | Last item number on page | 40 |
Basic Usage
<div dbind_collection="products" dbind_paginate="20">
<!-- Page info -->
<div class="page-info">
Showing <span dbind_page-info="from"></span>-<span dbind_page-info="to"></span>
of <span dbind_page-info="total"></span> products
</div>
<!-- Products -->
<div dbind_repeat="data">
<div class="product" dbind_data="name"></div>
</div>
<!-- Pagination -->
<div class="pagination-footer">
Page <span dbind_page-info="page"></span>
of <span dbind_page-info="totalPages"></span>
</div>
</div>Use Cases
1. Results Summary
<div class="search-results-header">
<h2>
Found <span dbind_page-info="total"></span> results
</h2>
<p class="results-range">
Showing <span dbind_page-info="from"></span> - <span dbind_page-info="to"></span>
</p>
</div>2. Table Footer
<table class="data-table">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Status</th>
</tr>
</thead>
<tbody dbind_repeat="data">
<tr>
<td dbind_data="name"></td>
<td dbind_data="email"></td>
<td dbind_data="status"></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3">
Page <span dbind_page-info="page"></span>/<span dbind_page-info="totalPages"></span>
(<span dbind_page-info="total"></span> total records)
</td>
</tr>
</tfoot>
</table>Collection Filtering
dbind_collection-filter
Purpose: Add filter controls that update the collection query.
Syntax:
<select dbind_collection-filter="collectionName" data-field="fieldName">
<option value="">All</option>
<option value="value1">Option 1</option>
</select>Basic Usage
<div dbind_collection="products">
<!-- Category filter -->
<select dbind_collection-filter="products" data-field="category">
<option value="">All Categories</option>
<option value="electronics">Electronics</option>
<option value="clothing">Clothing</option>
<option value="home">Home & Garden</option>
</select>
<!-- Status filter -->
<select dbind_collection-filter="products" data-field="status">
<option value="">All Status</option>
<option value="active">In Stock</option>
<option value="low">Low Stock</option>
<option value="out">Out of Stock</option>
</select>
<!-- Products -->
<div dbind_repeat="data" class="product-card">
<h3 dbind_data="name"></h3>
</div>
</div>Multiple Filters
Filters work together - selecting multiple narrows results:
<div dbind_collection="users">
<div class="filter-bar">
<select dbind_collection-filter="users" data-field="department">
<option value="">All Departments</option>
<option value="engineering">Engineering</option>
<option value="marketing">Marketing</option>
<option value="sales">Sales</option>
</select>
<select dbind_collection-filter="users" data-field="role">
<option value="">All Roles</option>
<option value="manager">Managers</option>
<option value="senior">Senior</option>
<option value="junior">Junior</option>
</select>
<select dbind_collection-filter="users" data-field="location">
<option value="">All Locations</option>
<option value="nyc">New York</option>
<option value="sf">San Francisco</option>
<option value="remote">Remote</option>
</select>
</div>
<div dbind_repeat="data" class="user-card">
<span dbind_data="name"></span>
</div>
</div>Collection Sorting
dbind_collection-sort
Purpose: Add sort controls that change the collection order.
Syntax:
<select dbind_collection-sort="collectionName">
<option value="field:asc">Field (A-Z)</option>
<option value="field:desc">Field (Z-A)</option>
</select>Basic Usage
<div dbind_collection="products">
<!-- Sort control -->
<select dbind_collection-sort="products">
<option value="name:asc">Name (A-Z)</option>
<option value="name:desc">Name (Z-A)</option>
<option value="price:asc">Price: Low to High</option>
<option value="price:desc">Price: High to Low</option>
<option value="rating:desc">Best Rated</option>
<option value="createdAt:desc">Newest First</option>
</select>
<div dbind_repeat="data" class="product">
<h3 dbind_data="name"></h3>
<span dbind_data="price" dbind_format="currency:USD"></span>
</div>
</div>Complete Example: E-commerce Catalog
<div class="product-catalog" dbind_collection="products" dbind_paginate="24">
<!-- Header with search and filters -->
<header class="catalog-header">
<h1>Our Products</h1>
<div class="search-box">
<input
type="search"
dbind_search="products"
placeholder="Search products..."
aria-label="Search products"
>
</div>
</header>
<!-- Filter and Sort Bar -->
<div class="filter-bar">
<div class="filters">
<select dbind_collection-filter="products" data-field="category" aria-label="Category">
<option value="">All Categories</option>
<option value="electronics">Electronics</option>
<option value="clothing">Clothing</option>
<option value="home">Home & Living</option>
<option value="sports">Sports</option>
</select>
<select dbind_collection-filter="products" data-field="brand" aria-label="Brand">
<option value="">All Brands</option>
<option value="apple">Apple</option>
<option value="samsung">Samsung</option>
<option value="sony">Sony</option>
</select>
<select dbind_collection-filter="products" data-field="priceRange" aria-label="Price Range">
<option value="">Any Price</option>
<option value="0-50">Under $50</option>
<option value="50-100">$50 - $100</option>
<option value="100-500">$100 - $500</option>
<option value="500+">$500+</option>
</select>
</div>
<div class="sort">
<label for="sort-select">Sort by:</label>
<select id="sort-select" dbind_collection-sort="products">
<option value="relevance:desc">Relevance</option>
<option value="price:asc">Price: Low to High</option>
<option value="price:desc">Price: High to Low</option>
<option value="rating:desc">Top Rated</option>
<option value="sales:desc">Best Selling</option>
<option value="createdAt:desc">Newest</option>
</select>
</div>
</div>
<!-- Results Info -->
<div class="results-info">
<span>
Showing <span dbind_page-info="from"></span>-<span dbind_page-info="to"></span>
of <span dbind_page-info="total"></span> products
</span>
</div>
<!-- Loading State -->
<div dbind_loading="show" class="loading-grid">
<div class="skeleton-card"></div>
<div class="skeleton-card"></div>
<div class="skeleton-card"></div>
<div class="skeleton-card"></div>
</div>
<!-- Product Grid -->
<div dbind_loading="hide" class="product-grid">
<article dbind_repeat="data" class="product-card">
<!-- Sale Badge -->
<span class="sale-badge" dbind_show="onSale">SALE</span>
<!-- Product Image -->
<a dbind_href="url" class="product-image">
<img dbind_src="image" dbind_alt="name" loading="lazy">
</a>
<!-- Product Info -->
<div class="product-info">
<span class="category" dbind_data="category"></span>
<h3><a dbind_href="url" dbind_data="name"></a></h3>
<!-- Rating -->
<div class="rating">
<span class="stars" dbind_data="ratingStars"></span>
<span class="count">(<span dbind_data="reviewCount"></span>)</span>
</div>
<!-- Price -->
<div class="price-container">
<span class="current-price" dbind_data="price" dbind_format="currency:USD"></span>
<span class="original-price" dbind_show="onSale" dbind_data="originalPrice" dbind_format="currency:USD"></span>
</div>
<!-- Stock Status -->
<span class="in-stock" dbind_if="stock>10">In Stock</span>
<span class="low-stock" dbind_if="stock<=10">Only <span dbind_data="stock"></span> left</span>
<span class="out-of-stock" dbind_if="stock==0">Out of Stock</span>
</div>
<!-- Add to Cart -->
<button class="btn-add-cart" dbind_unless="stock==0">Add to Cart</button>
<button class="btn-notify" dbind_if="stock==0">Notify Me</button>
</article>
</div>
<!-- Empty State -->
<div class="empty-state" dbind_empty="data">
<img src="/images/no-products.svg" alt="">
<h2>No products found</h2>
<p>Try adjusting your search or filter criteria.</p>
<button onclick="clearFilters()">Clear All Filters</button>
</div>
<!-- Pagination -->
<nav class="pagination" aria-label="Product pages">
<div class="page-info">
Page <span dbind_page-info="page"></span> of <span dbind_page-info="totalPages"></span>
</div>
</nav>
</div>CSS (excerpt):
.product-catalog {
max-width: 1200px;
margin: 0 auto;
}
.filter-bar {
display: flex;
justify-content: space-between;
gap: 1rem;
padding: 1rem 0;
border-bottom: 1px solid #e5e7eb;
}
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
padding: 2rem 0;
}
.product-card {
border: 1px solid #e5e7eb;
border-radius: 12px;
overflow: hidden;
transition: box-shadow 0.2s;
}
.product-card:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.loading-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1.5rem;
}
.skeleton-card {
height: 350px;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: skeleton 1.5s ease-in-out infinite;
border-radius: 12px;
}
@keyframes skeleton {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}Real-Time Updates
Collections can receive real-time updates when data changes on the server:
<div dbind_collection="notifications" dbind_live="true">
<div dbind_repeat="data" class="notification">
<span dbind_data="message"></span>
<time dbind_data="createdAt" dbind_format="date:relative"></time>
</div>
</div>When new data is added to the collection, it automatically appears in the DOM.
Next Steps
- Lists - Client-side list rendering
- Loading - Loading states and skeletons
- Formatting - Format collection data