Navigate Through Page Tree Using Sticky Buttons — Confluence Cloud Macro
This Confluence user macro uses the Confluence Cloud REST API to fetch the current page details, its ancestors, and direct children, then computes a depth-first “previous” and “next” page by combining child, sibling, and ancestor-sibling relationships. The macro resolves target pages to their web UI URLs and renders compact circular AUI-styled buttons that stick to the bottom-right of the viewport, dynamically adjusting position based on whether one or both navigation buttons are visible.
User Parameters
This macro comes without configurable user parameters.
Template
## Styles
#set($navBgColor = "transparent")
#set($navWidth = "4em")
#set($navTop = "92%")
#set($navRight = "3.7%")
## Max depth for child pages when finding the "deepest leaf" for BACK
#set($maxDepthDown = 20)
## PAGE CONTEXT (current, parent, ancestors)
## Ancestors: root first, direct parent last (may be null/empty)
#set($ancestors = $ConfluenceManager.get("/wiki/api/v2/pages/${page.id}/ancestors?limit=50").results)
## FORWARD NAVIGATION
## 1) First child
## 2) Next sibling of current or any ancestor
#set($forwardHref = "")
## --- FORWARD STEP 1: first child of current page ---
#set($children = $ConfluenceManager.get("/wiki/api/v2/pages/${page.id}/direct-children?limit=250").results)
#set($firstChildId = "")
#if($children)
#foreach($child in $children)
#if($child.type == "page")
#set($firstChildId = $child.id)
#break
#end
#end
#end
#if($firstChildId != "")
#set($nextPage = $ConfluenceManager.get("/wiki/api/v2/pages/${firstChildId}"))
#if($nextPage._links && $nextPage._links.webui)
#set($forwardHref = "${baseUrl}${nextPage._links.webui}")
#end
#else
## --- FORWARD STEP 2: next sibling at this level or above ---
#set($nextPageId = "")
## 2a) Next sibling of current page
#if($page.parentId)
#set($siblings = $ConfluenceManager.get("/wiki/api/v2/pages/${page.parentId}/direct-children?limit=250").results)
#set($afterCurrent = false)
#if($siblings)
#foreach($sibling in $siblings)
#if($sibling.type == "page")
#if($afterCurrent && $nextPageId == "")
#set($nextPageId = $sibling.id)
#end
#if($sibling.id == $page.id)
#set($afterCurrent = true)
#end
#end
#end
#end
#end
## 2b) If still none, next sibling of ancestors (nearest → farthest)
#if($nextPageId == "" && $ancestors)
#set($ancestorCount = $ancestors.size())
#foreach($ignored in $ancestors)
#if($nextPageId == "")
## Walk from direct parent up toward root using reverse index
#set($reverseIndex = $ancestorCount - $foreach.count)
#set($ancestor = $ancestors.get($reverseIndex))
## Skip top ancestor (no parent above it)
#if($reverseIndex > 0)
#set($parentIndex = $reverseIndex - 1)
#set($ancestorParent = $ancestors.get($parentIndex))
#set($ancestorParentId = $ancestorParent.id)
#set($ancestorSiblings = $ConfluenceManager.get("/wiki/api/v2/pages/${ancestorParentId}/direct-children?limit=250").results)
#set($afterAncestor = false)
#if($ancestorSiblings)
#foreach($sibling2 in $ancestorSiblings)
#if($sibling2.type == "page")
#if($afterAncestor && $nextPageId == "")
#set($nextPageId = $sibling2.id)
#end
#if($sibling2.id == $ancestor.id)
#set($afterAncestor = true)
#end
#end
#end
#end
#end
#end
#end
#end
## Resolve nextPageId to URL
#if($nextPageId != "")
#set($nextPage = $ConfluenceManager.get("/wiki/api/v2/pages/${nextPageId}"))
#if($nextPage._links && $nextPage._links.webui)
#set($forwardHref = "${baseUrl}${nextPage._links.webui}")
#end
#end
#end
## BACKWARD NAVIGATION (←)
## prev(page) =
## - deepest leaf under previous sibling, if it exists
## - otherwise parent
#set($backHref = "")
#set($backTargetId = "")
## --- BACK STEP 1: previous sibling of current page ---
#set($prevSiblingId = "")
#if($page.parentId)
#set($backSiblings = $ConfluenceManager.get("/wiki/api/v2/pages/${page.parentId}/direct-children?limit=250").results)
#if($backSiblings)
#foreach($sibling in $backSiblings)
#if($sibling.type == "page")
#if($sibling.id == $page.id)
#break
#else
## Last page before current in this list
#set($prevSiblingId = $sibling.id)
#end
#end
#end
#end
#end
## --- BACK STEP 2: deepest leaf under previous sibling or parent ---
#if($prevSiblingId != "")
## Drill down into previous sibling's subtree to the deepest leaf
#set($backTargetId = $prevSiblingId)
#foreach($depth in [1..$maxDepthDown])
#set($downChildren = $ConfluenceManager.get("/wiki/api/v2/pages/${backTargetId}/direct-children?limit=250").results)
#set($lastChildId = "")
#if($downChildren)
#foreach($child in $downChildren)
#if($child.type == "page")
#set($lastChildId = $child.id)
#end
#end
#end
#if($lastChildId != "")
#set($backTargetId = $lastChildId)
#else
#break
#end
#end
#elseif($page.parentId)
## No previous sibling → use parent as previous page
#set($backTargetId = $page.parentId)
#end
## Resolve backTargetId to URL
#if($backTargetId != "")
#set($backTargetPage = $ConfluenceManager.get("/wiki/api/v2/pages/${backTargetId}"))
#if($backTargetPage._links && $backTargetPage._links.webui)
#set($backHref = "${baseUrl}${backTargetPage._links.webui}")
#end
#end
## Button positions
#set($hasBack = false)
#set($hasForward = false)
#if($backHref != "")
#set($hasBack = true)
#end
#if($forwardHref != "")
#set($hasForward = true)
#end
#if($hasBack && $hasForward)
#set($navRight = "5.3%")
#elseif($hasBack || $hasForward)
#set($navRight = "3.75%")
#end
## RENDER NAVIGATION UI
<div class="aui-dialog2 aui-layer"
style="
top: $navTop;
height: 80em;
right: $navRight;
display: block;
visibility: hidden;
z-index: 10;
">
<div style="
padding: 0.4em;
float: right;
width: $navWidth;
background-color: $navBgColor;
height: auto;
visibility: visible;
overflow: hidden;
text-align: center;
">
#if($backHref != "")
<a href="$backHref"
title="Previous page"
style="
z-index: 9999;
text-decoration: none;
color: var(--ds-text-subtle, #44546F);
border: 1px solid grey;
outline: none;
border-radius: 50%;
display: inline-block;
width: 25px;
height: 25px;
text-align: center;
font-size: 16px;
margin-right: 4px;
">
←
</a>
#end
#if($forwardHref != "")
<a href="$forwardHref"
title="Next page"
style="
z-index: 9999;
text-decoration: none;
color: var(--ds-text-subtle, #44546F);
border: 1px solid grey;
outline: none;
border-radius: 50%;
display: inline-block;
width: 25px;
height: 25px;
text-align: center;
font-size: 16px;
">
→
</a>
#end
</div>
</div>Recommended Macros
Shows all attachments from the current space in a table view
Display Confluence users filtered by their email addresses.
Shows a mention of the user who created the current page. If it's a current user, mention blue. If it's another user, mention gray.
Fetch a random quote from the DummyJSON API and display it in a stylized blockquote format.
Create dropdown menus in Confluence Cloud with predefined sets of options and permission gates
Add a configurable sticky banner to a Confluence page
Show confetti bursts and a motivational message upon saving an edited page
Display Jira issue comments in a table