Skip to content

Chapter 6 - Load more Authors

On the Author page, we display a list of all resources published by (or featuring) a given author.

When an author has more than 9 resources, a “Load more” button appears at the end of the list, allowing users to fetch additional results without reloading the page.


  1. When the user clicks “Load more”:
    • A JavaScript handler is triggered.
    • A loading spinner is shown.
  2. The handler updates the pagination parameters:
    • start: first index of the next batch
    • end: last index of the next batch
  3. A new request is sent to Sanity:
    • Sanity returns the next 9 resources.
  4. The returned resources:
    • Are rendered through an internal endpoint (/api/v1/render-content-authors/)
    • Are appended dynamically to the DOM
  5. When there are no more results:
    • The “Load more” button is hidden.

Inside the author template (pages/[lang]/author/[slug].astro) we define:

  • The list container
  • The “Load more” container
  • The button
  • A hidden field containing the authorId
pages/[lang]/author/[slug].astro
<div class="f--container js--author-list">
...
<div class="f--row f--gap-a u--pt-10 u--pt-tablets-7 js--load-more-container">
<div class="f--col-12 u--display-flex u--justify-content-center">
<button class="c--btn-a js--load-more-resources">
{single.load_more_text.text}
</button>
</div>
<input type="hidden" class="js--author-id" value={single.id} />
</div>
</div>

Note: the hidden input is required to build the GROQ query client-side and fetch more resources for the correct au> thor.

Define the GROQ query on the initial page load.

service/query/single/people.js
"resources" : *[_type in ['blogs', 'webinars', 'podcasts','research'] &&
(author._ref == ^._id || ^._id in speakers[].speaker._ref || ^._id in authors[].author._ref)]|
order(date desc)[0..8] {
"type": _type,
"card": {${resource({language, isReference: false})}}
}

[0..8] = 9 items. Ordered by date descending. Includes resources where the person appears as: author, speaker, authors[]

DOM References and Initial Pagination State (hitsPerPage, start, end, language)

Section titled “DOM References and Initial Pagination State (hitsPerPage, start, end, language)”
scripts/handler/author/LoadMore.js
this.DOM = {
loadMoreContainer :document.querySelector(".js--load-more-container"),
loadMoreBtn : document.querySelector(".js--load-more-resources"),
authorID : document.querySelector(".js--author-id")?.value,
resultsContainer : document.querySelector(".js--results"),
}
// Settings
this.language = getCookie("preferred_lang") || "en"; // Default to English
this.hitsPerpage = 9; // Number of results per load
this.start = this.hitsPerpage;
this.end = this.hitsPerpage + this.start - 1;
this.contentPosition = "beforebegin"; // Default insert position for new HTML
this.emitter = payload.emitter;
scripts/handler/author/LoadMore.js
async loadMoreAuthors() {
...
const query = `*[_type == 'people' && _id == '${this.DOM.authorID}'][0]{
"resources": *[_type in ['blogs', 'webinars', 'podcasts','research']
&& (author._ref == ^._id || ^._id in speakers[].speaker._ref || ^._id in authors[].author._ref)] | order(date desc)
[${this.start} .. ${this.end}] {
"type": _type,
"card": {${resource({ language: this.language, isReference: false })}}
},
"total": count(*[_type in ['blogs', 'webinars', 'podcasts','research']
&& (author._ref == ^._id || ^._id in speakers[].speaker._ref || ^._id in authors[].author._ref)])
}`;
const { result } = await sanityClient.fetch(query, {}, { filterResponse: false });
this.total = result?.total || 0;
const cards = result?.resources || [];
...
}

 Render the result and apply to the HTML/Astro

Section titled “ Render the result and apply to the HTML/Astro”
async loadMoreAuthors() {
...
let resultContent = "";
try {
const res = await fetch("/api/v1/render-content-authors/", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
data: cards,
language: this.language,
resultsTotal: this.total,
}),
});
const renderResult = await res.json();
resultContent = renderResult.result || "";
} catch (err) {
console.error("Error in fetch render-content:", err);
}
}

The “Load more” pattern on Author pages works as follows:

  • Astro renders the first 9 resources at build/load time.
  • JS handles incremental pagination via GROQ [start..end].
  • Cards are rendered through an internal API.
  • New items are appended to the DOM.
  • The “Load more” button disappears once all resources are loaded.

Algolia