FaceFlow Lists — Dynamic Content Listings
The List system in FaceFlow enables you to create dynamic, data-driven pages that query and display collections of content — blog archives, product catalogs, team directories, portfolios, and more. Lists combine a powerful query builder with flexible rendering options (card layout or custom Handlebars templates) and built-in AJAX pagination.
List Developer Docs
Lists are the dynamic content layer in FaceFlow.
They allow technical users to define how content collections are selected, rendered, paginated, and published inside a Page experience without converting every archive or directory into manual page editing.
Core Responsibility
A List is responsible for:
- selecting a content set
- sorting and limiting results
- rendering each item consistently
- paginating larger collections
- exposing a predictable browsing contract
Lists should answer one clear question: "what collection is this page responsible for presenting?"
List Model
A typical List combines:
- a query definition
- a result ordering strategy
- a page size
- a rendering mode
- optional custom fields
- optional item template logic
Conceptually:
{
"name": "resource-library",
"query": {
"template": "resource-item",
"parent": "/resources/",
"sort": "-published",
"limit": 12
},
"display": {
"mode": "custom-template",
"pagination": true
}
}Query Contract
Technical teams should keep List queries explicit and bounded.
Typical inputs include:
- content type
- section boundary
- sorting
- result limit
- additional filter constraints
A weak query creates weak output. If the content boundary is vague, the List quickly becomes a dumping ground.
Example:
template=resource-item, parent=/resources/, sort=-published, limit=12That query is understandable. A catch-all archive with several unrelated types usually is not.
Query Design Example
Good List definitions usually keep the selection rule and display rule separate:
{
"name": "case-studies",
"query": {
"template": "case-study",
"parent": "/customers/",
"sort": "-published",
"limit": 9
},
"display": {
"mode": "custom-template",
"pagination": true
}
}That makes it easier to review whether the content boundary is correct before discussing presentation.
Rendering Modes
Lists usually follow one of two models.
Card-style output
Use this when:
- editors need a low-friction configuration path
- the archive follows a standard visual pattern
- one consistent card contract is enough
Custom template output
Use this when:
- result items need richer mapping
- the design is not a simple card grid
- metadata, badges, or media need custom placement
- the archive depends on Facet logic
Example custom item output:
<div class="resource-grid">
{{#each items}}
<article class="resource-card">
<a href="{{ this.url }}">
<h3>{{ this.title }}</h3>
<p>{{ this.summary }}</p>
</a>
</article>
{{/each}}
</div>Pagination
Pagination is part of the List contract, not just a visual detail.
Technical review should define:
- default page size
- page count behavior
- navigation pattern
- empty-state behavior
Conceptually:
page 1 -> items 1-12
page 2 -> items 13-24
page 3 -> items 25-36If a List is expected to grow, pagination should be intentional from the first release.
Relationship to Pages and Components
The clean mental model is:
- Layout provides the shell
- Page provides the publishable route and surrounding experience
- List provides the dynamic collection
- Component may provide supporting sections around the List
Example page composition:
resource-layout
-> archive-hero component
-> resource-library list
-> newsletter-signup componentThis keeps dynamic browsing separate from one-off page content.
List Template Example
<section class="archive">
<header class="archive-header">
<h1>{{ page.title }}</h1>
</header>
<div class="archive-items">
{{#each items}}
<article class="archive-item">
<a href="{{ this.url }}">{{ this.title }}</a>
</article>
{{/each}}
</div>
{{#if pagination}}
<nav class="archive-pagination">
{{{ pagination.links }}}
</nav>
{{/if}}
</section>The goal is a stable contract between the List query and the archive template.
Empty-State and Growth Rules
Technical review should also account for what happens when the collection changes shape:
- no results
- one result
- many pages of results
- missing optional fields on some items
A List template is only stable if it survives all four conditions without layout breakage or confusing output.
Technical Review Checklist
- is the query boundary clear and narrow?
- does sorting match the browsing intent?
- can the template handle growth in result volume?
- is pagination part of the design contract?
- is the List solving one archive problem, not several unrelated ones?
Anti-Patterns
Avoid:
- mixing unrelated content types into one archive just because they are available
- building an archive entirely by hand with repeated manual cards
- using one List for several visual modes with incompatible contracts
- leaving result ordering implicit
- ignoring empty states and pagination until content volume becomes a problem