Stand with Ukraine 🇺🇦

Dynamic table listing child pages — Confluence Cloud Macro

adminformattingconfluence-contentreporting

This macro automatically lists all child pages of the current Confluence page in a sortable and filterable table.

It retrieves child pages via the Confluence Cloud REST API and displays key metadata including:

• Page name with clickable link

• Creation date

• Author with user profile link

• Labels with links to label-based search

For convenience, the macro also includes a search field above the table. Users can type any keyword, and the list instantly filters across page names, authors, and labels, making it much easier to navigate spaces with many child pages.

This macro is especially useful for knowledge bases, technical documentation, or structured parent–child page hierarchies where teams need visibility and quick access to child content.

Unlike the default “Child Pages” macro, this solution supports metadata columns and client-side filtering, giving more flexibility and interactivity.

✅ Requires the User Macro for Confluence Cloud app

Try for free

User Parameters

This macro comes without configurable user parameters.

Template

<style>
  tr.row-hidden {
    visibility: collapse;
  }
</style>

#set ($children = $ConfluenceManager.get("/wiki/api/v2/pages/$page.id/direct-children"))
#set ($format = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")

<input
  type="text"
  id="filterInput"
  placeholder="Filter by name..."
  style="margin-bottom:10px;padding:5px;width:200px;border:2px solid #0B120E24;border-radius:4px;"
/>

<table class="aui aui-table-sortable" id="pagesTable" cellspacing="0" cellpadding="5" style="border:none;">
  <thead>
    <tr>
      <th>Name</th>
      <th>Created Date</th>
      <th>Created By</th>
      <th>Labels</th>
    </tr>
  </thead>
  <tbody>
    #foreach ($child in $children.results)
      #set ($childPage = $ConfluenceManager.get("/wiki/api/v2/pages/$child.id?include-labels=true"))
      #set ($pageLink = "$childPage._links.base$childPage._links.webui")

      <tr>
        <td><a href="$pageLink" target="_blank">$childPage.title</a></td>
        <td>$DateUtils.parseDate($childPage.createdAt, $format)</td>

        #set ($isCurrentUser = $StringUtils.equals($user.accountId, $childPage.authorId))
        #if ($isCurrentUser)
          #set ($blueStyle = "aui-lozenge-inprogress")
          #set ($author = $user)
        #else
          #set ($blueStyle = "aui-lozenge-subtle")
          #set ($author = $ConfluenceManager.get("/wiki/rest/api/user?accountId=$childPage.authorId"))
        #end

        <td>
          <a href="${baseUrl}/people/${author.accountId}">
            <span class="aui-lozenge $blueStyle">@${author.displayName}</span>
          </a>
        </td>

        <td>
          #foreach ($label in $childPage.labels.results)
            <a href="${baseUrl}/search?product=confluence&labels=${label.name}">
              <span class="aui-lozenge aui-lozenge-subtle">$label.name</span>
            </a>
          #end
        </td>
      </tr>
    #end
  </tbody>
</table>

<script>
(function () {
  const input = document.getElementById("filterInput");
  const rows = document.querySelectorAll("#pagesTable tbody tr");

  input.addEventListener("input", function () {
    const filter = this.value.toLowerCase().trim();

    rows.forEach(row => {
      const cells = row.cells;
      const rowText = (
        cells[0].textContent + " " +
        cells[2].textContent + " " +
        cells[3].textContent
      ).toLowerCase();

      row.classList.toggle("row-hidden", !rowText.includes(filter));
    });
  });
})();
</script>