Page recipe R8
Catalog
A filterable list: page head with search, filter panel, results bar, card grid, pager, a no-results state and the closing CTA band. Build it in code.
- Page kind
- utility
- Serves
- /scholarship-directory, /benefits, /search/node
- Base page
- /scholarship-directory
- Components
- Page head, Search, Filter, Results bar, Card, Status, Numbered pager, Empty state, Result, Filter chips and tags, Tier badge, CTA band, Band and container, Heading, Eyebrow
- Markdown
- /recipes/r8-catalog.md
Overview
Serves: the scholarship directory /scholarship-directory, the benefits list /benefits and site search /search/node. Base page: /scholarship-directory. Page kind: utility (the visitor looks for one item, then acts on it). All recipes
How to use this recipe: it shows a proven page shape, not a fixed template. Start from the closest recipe, choose the components that fit the content, combine them as needed and leave out what does not fit. Only the component rules are fixed: grounds, one gold element per viewport, heading order, marks and the rules on each component page.
Build it in code. Every card, count, filter value and page link comes from records. The filter state lives in the URL (GET), so a filtered page has an address, the back button keeps it and the page works without JavaScript.
Sections of the base page (ground in brackets):
- Page head [soft]: eyebrow, H1, lead, the large search. Its gold button is the band's one action.
- Our own items [white]: band head and a short card grid. Only on the first page with no filter and no keyword. The directory shows the Honor Society® scholarships here, the awards applied for on this site.
- Catalog [soft]: band head, filter panel, results bar, card grid (24 per page), pager. With no match, the grid and the pager give way to the no-results state.
- CTA band [navy]: closing band, one gold button.
Components: page-head, search (--large), filter, results-bar, card (--award, --offer, --article, --place), status, pager, empty-state (--search), result (site search), chips (site search type chips), tier-badge, cta-band.
Rules:
- One card anatomy for every item: type label or value, title, one line of facts, short text, tags, a foot with a status and at most one action. Leave out empty slots.
- The filter panel sits above the results, never in a sidebar. Two to four selects. Option labels are visitor words from a curated map in code, never raw tags.
- Numbered pager, 24 items per page. Every page link is a real URL (
?page=2). - Counts come from the query: the results-bar count, the filter count, the pager. Never type a count.
- A filtered or keyword state prints
noindex,followand a canonical link to the clean URL. - Card links use the item's alias, never
taxonomy/term/Nornode/N. - The page head search button and the CTA band button are the page's only gold elements. The site header's Join button is chrome and does not count.
- Load
filter.json the page. This recipe page loads no script, so the filter panel shows its summary at every width, as it does without the script. Try the open row on the Filter page.
Live page
The scholarship directory, first page, no filter. Sample items are fictional.
Scholarships
Scholarship directory
Awards from Honor Society® and other providers, each with its own eligibility, deadline and application.
Honor Society® scholarships
Our own awards. You apply for these on our site.
All scholarships
Honor Society® membership
Apply for our own scholarships
Members apply for Honor Society scholarships on our site and see new awards first.
Page HTML (80 lines)
<!-- PAGE HEAD: printed by the template (hs_core_page_head, with the search in its body slot). Two steps deep: no breadcrumb. -->
<section class="hs-band hs-band--soft hs-page-head" data-section="hero">
<div class="hs-container">
<p class="hs-eyebrow">Scholarships</p>
<h1 class="hs-heading hs-heading--h1 hs-heading--rule">Scholarship directory</h1>
<p class="hs-lead hs-page-head__lead">Awards from Honor Society® and other providers, each with its own eligibility, deadline and application.</p>
<form class="hs-search hs-search--large" role="search" method="get" action="/scholarship-directory">
<label class="hs-visually-hidden" for="r8-q">Search scholarships</label>
<input class="hs-control hs-search__input" id="r8-q" type="search" name="q" placeholder="nursing, study abroad">
<button class="hs-button hs-search__button" type="submit">Search</button>
</form>
</div>
</section>
<!-- OUR OWN ITEMS: first page, no filter, no keyword only. Amounts are parsed from the name when it starts with one; deadlines come from the award data. -->
<section class="hs-band" data-section="our-scholarships" aria-labelledby="r8-own-h">
<div class="hs-container">
<div class="hs-band__head">
<h2 class="hs-heading hs-heading--h2 hs-heading--rule" id="r8-own-h">Honor Society® scholarships</h2>
<p class="hs-lead">Our own awards. You apply for these on our site.</p>
</div>
<ul class="hs-card-grid hs-card-grid--3">
<li><a class="hs-card hs-card--link hs-card--award" href="/example-leadership-award" data-ph-capture-attribute-cta="scholarship" data-ph-capture-attribute-cta-loc="our-scholarships"><p class="hs-card__value">$2,500</p><h3 class="hs-card__title">Example Leadership Award</h3><ul class="hs-card__meta"><li>Honor Society®</li><li>Undergraduate</li></ul><div class="hs-card__foot"><span class="hs-status hs-status--open">Open</span><p class="hs-card__meta">Deadline <time datetime="2026-12-15">December 15, 2026</time></p></div></a></li>
<li><a class="hs-card hs-card--link hs-card--award" href="/example-service-award" data-ph-capture-attribute-cta="scholarship" data-ph-capture-attribute-cta-loc="our-scholarships"><p class="hs-card__value">$1,000</p><h3 class="hs-card__title">Example Service Award</h3><ul class="hs-card__meta"><li>Honor Society®</li><li>Any student</li></ul><div class="hs-card__foot"><span class="hs-status hs-status--soon">Closing soon</span><p class="hs-card__meta">Deadline <time datetime="2026-10-31">October 31, 2026</time></p></div></a></li>
<li><a class="hs-card hs-card--link hs-card--award" href="/example-study-abroad-award" data-ph-capture-attribute-cta="scholarship" data-ph-capture-attribute-cta-loc="our-scholarships"><p class="hs-eyebrow">Scholarship</p><h3 class="hs-card__title">Example Study Abroad Award</h3><ul class="hs-card__meta"><li>Honor Society®</li><li>Undergraduate</li></ul><div class="hs-card__foot"><span class="hs-status hs-status--closed">Closed</span></div></a></li>
</ul>
</div>
</section>
<!-- CATALOG: server-side GET over the full list. The filter form keeps q as a hidden field. -->
<section class="hs-band hs-band--soft" data-section="catalog" aria-labelledby="r8-all-h">
<div class="hs-container">
<div class="hs-band__head">
<h2 class="hs-heading hs-heading--h2 hs-heading--rule" id="r8-all-h">All scholarships</h2>
</div>
<form class="hs-filter" id="r8-filter" method="get" action="/scholarship-directory">
<details class="hs-filter__panel" data-hs-filter>
<summary class="hs-filter__summary">Filters</summary>
<div class="hs-filter__fields">
<div class="hs-field hs-filter__field"><label class="hs-label" for="r8-for">Who it’s for</label><select class="hs-control" id="r8-for" name="for"><option value="">Anyone</option><option value="undergraduate">Undergraduate</option><option value="graduate">Graduate</option><option value="alumni">Alumni</option><option value="international">International</option><option value="multicultural">Multicultural</option></select></div>
<div class="hs-field hs-filter__field"><label class="hs-label" for="r8-type">Type</label><select class="hs-control" id="r8-type" name="type"><option value="">Any type</option><option value="scholarship">Scholarship</option><option value="grant">Grant</option><option value="fellowship">Fellowship</option><option value="internship">Internship</option><option value="research">Research</option><option value="study-abroad">Study abroad</option><option value="tuition">Tuition assistance</option></select></div>
<div class="hs-field hs-filter__field"><label class="hs-label" for="r8-by">Offered by</label><select class="hs-control" id="r8-by" name="by"><option value="">Any provider</option><option value="honor-society">Honor Society®</option><option value="bold">Bold.org</option><option value="other">Other providers</option></select></div>
<div class="hs-filter__actions"><button class="hs-button hs-button--navy hs-button--sm" type="submit">Apply filters</button></div>
</div>
</details>
</form>
<div class="hs-results-bar">
<p class="hs-results-bar__count" role="status"><strong>1,003</strong> scholarships</p>
<div class="hs-results-bar__sort"><label class="hs-label" for="r8-sort">Sort by</label><select class="hs-control" id="r8-sort" name="sort" form="r8-filter"><option value="">Name, A to Z</option><option value="amount">Amount, highest first</option></select><button class="hs-button hs-button--secondary hs-button--sm hs-results-bar__apply" type="submit" form="r8-filter" data-hs-filter-apply>Sort</button></div>
</div>
<!-- 24 cards per page; 3 shown. -->
<ul class="hs-card-grid hs-card-grid--3">
<li><a class="hs-card hs-card--link hs-card--award" href="/scholarships/example-community-grant" data-ph-capture-attribute-cta="scholarship" data-ph-capture-attribute-cta-loc="catalog"><p class="hs-card__value">$5,000</p><h3 class="hs-card__title">Example Community Grant</h3><ul class="hs-card__meta"><li>examplefoundation.org</li><li>Graduate</li></ul><p class="hs-card__text">For graduate students who plan a career in public health.</p></a></li>
<li><a class="hs-card hs-card--link hs-card--award" href="/scholarships/sample-arts-fellowship" data-ph-capture-attribute-cta="scholarship" data-ph-capture-attribute-cta-loc="catalog"><p class="hs-eyebrow">Fellowship</p><h3 class="hs-card__title">Sample Arts Fellowship</h3><ul class="hs-card__meta"><li>Bold.org</li><li>Undergraduate</li></ul><p class="hs-card__text">A year of support for a student in the visual or performing arts.</p></a></li>
<li><a class="hs-card hs-card--link hs-card--award" href="/scholarships/placeholder-stem-award" data-ph-capture-attribute-cta="scholarship" data-ph-capture-attribute-cta-loc="catalog"><p class="hs-card__value">$1,500</p><h3 class="hs-card__title">Placeholder STEM Award</h3><ul class="hs-card__meta"><li>sampleinstitute.org</li><li>Multicultural</li></ul><p class="hs-card__text">For first-generation students in science, technology, engineering or math.</p></a></li>
</ul>
<nav class="hs-pager" aria-label="Pages">
<ul class="hs-pager__list">
<li class="hs-pager__item"><a class="hs-pager__link" href="?page=1" aria-current="page">1</a></li>
<li class="hs-pager__item"><a class="hs-pager__link" href="?page=2">2</a></li>
<li class="hs-pager__item"><a class="hs-pager__link" href="?page=3">3</a></li>
<li class="hs-pager__item"><span class="hs-pager__gap" aria-hidden="true">…</span></li>
<li class="hs-pager__item"><a class="hs-pager__link" href="?page=42">42</a></li>
<li class="hs-pager__item"><a class="hs-pager__link" href="?page=2" rel="next"><span class="hs-pager__word">Next</span><svg class="hs-pager__arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M9 6l6 6-6 6"/></svg></a></li>
</ul>
</nav>
</div>
</section>
<!-- CTA BAND: the closing band. One gold button. -->
<section class="hs-band hs-band--navy hs-cta-band" data-section="join">
<div class="hs-container hs-cta-band__inner">
<p class="hs-eyebrow">Honor Society® membership</p>
<h2 class="hs-heading hs-heading--h2">Apply for our own scholarships</h2>
<p class="hs-lead">Members apply for Honor Society scholarships on our site and see new awards first.</p>
<div class="hs-actions hs-cta-band__actions">
<a class="hs-button" href="/join" data-ph-capture-attribute-cta="join" data-ph-capture-attribute-cta-loc="join">Start your membership</a>
</div>
</div>
</section>No results
The catalog band when the filters and the keyword match nothing. The grid and the pager give way to the empty state.
All scholarships
No scholarships match “nursng” for alumni.
Check the spelling or remove a filter. You can also clear all filters.
Popular pages
Page HTML (23 lines)
<section class="hs-band hs-band--soft" data-section="catalog" aria-labelledby="r8n-h">
<div class="hs-container">
<div class="hs-band__head">
<h2 class="hs-heading hs-heading--h2 hs-heading--rule" id="r8n-h">All scholarships</h2>
</div>
<div class="hs-results-bar">
<p class="hs-results-bar__count" role="status"><strong>0</strong> scholarships for “nursng”</p>
<ul class="hs-results-bar__active" aria-label="Active filters">
<li><a class="hs-chip hs-results-bar__remove" href="/scholarship-directory?q=nursng"><span class="hs-visually-hidden">Remove filter: </span>Alumni</a></li>
<li><a class="hs-form-link" href="/scholarship-directory">Clear all</a></li>
</ul>
</div>
<div class="hs-empty hs-empty--search">
<h3 class="hs-empty__title">No scholarships match “nursng” for alumni.</h3>
<p class="hs-empty__text">Check the spelling or remove a filter. You can also <a href="/scholarship-directory">clear all filters</a>.</p>
<p class="hs-empty__links-title">Popular pages</p>
<ul class="hs-link-list hs-empty__links">
<li class="hs-link-list__item"><a class="hs-link-list__link" href="/scholarship-directory?for=graduate" data-ph-capture-attribute-cta="directory-graduate" data-ph-capture-attribute-cta-loc="no-results">Graduate scholarships</a></li>
<li class="hs-link-list__item"><a class="hs-link-list__link" href="/benefits" data-ph-capture-attribute-cta="benefits" data-ph-capture-attribute-cta-loc="no-results">Member benefits</a></li>
</ul>
</div>
</div>
</section>Site search
The search page on the same shape: type chips in place of the filter selects, result rows in place of cards. The result title is h2: the rows sit right under the H1.
Search
Scholarship Open
$2,500 Example Leadership Award
/example-leadership-award
An award for students who show leadership through a service project on their campus.
Benefit
Example Learning Co.
/benefits/example-learning-co
20% off online courses in leadership, management and public speaking.
Article
Five habits of student leaders
/articles/example-article
What student leadership looks like in a club, a lab and a part-time job.
Page HTML (38 lines)
<section class="hs-band hs-band--soft hs-page-head" data-section="hero">
<div class="hs-container">
<h1 class="hs-heading hs-heading--h1 hs-heading--rule">Search</h1>
<form class="hs-search hs-search--large" role="search" method="get" action="/search/node">
<label class="hs-visually-hidden" for="r8s-q">Search honorsociety.org</label>
<input class="hs-control hs-search__input" id="r8s-q" type="search" name="q" value="leadership">
<button class="hs-button hs-button--navy hs-search__button" type="submit">Search</button>
</form>
</div>
</section>
<section class="hs-band" data-section="results" aria-label="Search results">
<div class="hs-container">
<nav aria-label="Result type">
<ul class="hs-chips hs-chips--scroll">
<li><a class="hs-chip" href="/search/node?q=leadership" aria-current="page">All</a></li>
<li><a class="hs-chip" href="/search/node?q=leadership&type=scholarship">Scholarships</a></li>
<li><a class="hs-chip" href="/search/node?q=leadership&type=benefit">Benefits</a></li>
<li><a class="hs-chip" href="/search/node?q=leadership&type=article">Articles</a></li>
<li><a class="hs-chip" href="/search/node?q=leadership&type=page">Pages</a></li>
</ul>
</nav>
<div class="hs-results-bar">
<p class="hs-results-bar__count" role="status"><strong>38</strong> results for “leadership”</p>
</div>
<ol class="hs-results">
<li class="hs-result"><p class="hs-result__type">Scholarship <span class="hs-status hs-status--open">Open</span></p><h2 class="hs-result__title"><a href="/example-leadership-award" data-ph-capture-attribute-cta="result" data-ph-capture-attribute-cta-loc="results">$2,500 Example Leadership Award</a></h2><p class="hs-result__path">/example-leadership-award</p><p class="hs-result__text">An award for students who show <strong>leadership</strong> through a service project on their campus.</p></li>
<li class="hs-result"><p class="hs-result__type">Benefit</p><h2 class="hs-result__title"><a href="/benefits/example-learning-co" data-ph-capture-attribute-cta="result" data-ph-capture-attribute-cta-loc="results">Example Learning Co.</a></h2><p class="hs-result__path">/benefits/example-learning-co</p><p class="hs-result__text">20% off online courses in <strong>leadership</strong>, management and public speaking.</p></li>
<li class="hs-result"><p class="hs-result__type">Article</p><h2 class="hs-result__title"><a href="/articles/example-article" data-ph-capture-attribute-cta="result" data-ph-capture-attribute-cta-loc="results">Five habits of student leaders</a></h2><p class="hs-result__path">/articles/example-article</p><p class="hs-result__text">What student <strong>leadership</strong> looks like in a club, a lab and a part-time job.</p></li>
</ol>
<nav class="hs-pager" aria-label="Pages">
<ul class="hs-pager__list">
<li class="hs-pager__item"><a class="hs-pager__link" href="?q=leadership&page=1" aria-current="page">1</a></li>
<li class="hs-pager__item"><a class="hs-pager__link" href="?q=leadership&page=2">2</a></li>
<li class="hs-pager__item"><a class="hs-pager__link" href="?q=leadership&page=2" rel="next"><span class="hs-pager__word">Next</span><svg class="hs-pager__arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M9 6l6 6-6 6"/></svg></a></li>
</ul>
</nav>
</div>
</section>Notes
Scholarship directory:
- The first band lists the site's own awards only on the unfiltered first page. Each card links to the internal award page by its root-relative path.
- Filters: who it is for, type, offered by, plus the keyword. A curated map in code turns tag ids into these visitor words; imported school names are not filter values.
- The card value is the amount parsed from the name when the name starts with one ("$1,000 …"). With no amount, the card shows the type as an eyebrow. No invented figures.
- Filtered and keyword states:
noindex,follow, canonical to/scholarship-directory. The meta title names the page plainly.
Benefits on this recipe:
- Benefits use
hs-card--offerwith one small action, andis-lockedwith a--lockedstatus for a tier above the viewer's. - Order: the benefits the viewer can use now first ("Ready to use"), then the higher tiers. One upsell band for the tiers, not one per tier.
- The list is short (about 40 items), so it filters in the page on the same filter markup. The filter selects still work as a GET form without JavaScript.
- Keep the existing JS hooks and AJAX targets of the benefits module; where a class changes, change the script with it.
Site search on this recipe:
- One ranked list with type chips (All, Scholarships, Benefits, Articles, Pages) and a type label on each row. University stubs stay out of the list unless a type asks for them.
- The keyword is printed escaped in the field, the count and the empty state. No author names on rows.
- No results: the
hs-empty--searchstate with a spelling tip, a clear-filter link and popular pages. Result pages printnoindex,follow.
Dynamic parts that need code: every card, the counts, the filter options and their selected state, the active filter chips and their remove links, the pager, the canonical and robots tags.
The hs_mcp validator: not used. This page is built in code: details[open], data-hs-filter and form attributes are template output.