Interfaces & Types
Navigation’s queries return the interfaces and types on this page. Nodes share one interface, with a concrete type for each menu, so you can request menu-specific custom fields with an inline fragment. Context and breadcrumb queries return their own small types.
Node Interfaces and Types
The NodeInterface Interface
Every node returned by navigationNodes, navigationNode, a Navigation field or a node’s children implements NodeInterface. Saved nodes resolve to their menu’s [handle]_Node type, and nodes a Dynamic node generates resolve to ProjectedNavigationNode.
The interface includes Craft’s element and structure fields, such as id, uid, title, slug, uri, enabled, siteId, siteHandle, language, dateCreated, dateUpdated, level, lft, rgt and structureId. Craft’s GraphQL docs (opens new window) describe those. Navigation adds the following fields.
The node’s child nodes, one level down. Children generated by a Dynamic node are included unless the query passed withProjectedChildren: false. The field shows node query arguments in the schema, but they don’t filter the children, so filter the list in your frontend when you need fewer.
The extra CSS classes an editor gave this node, as a space-separated string. It’s null when none are set.
The extra HTML attributes an editor gave this node, each as a NodeCustomAttribute with an attribute name and a value. It’s an empty list when none are set.
The node type’s own settings, encoded as a JSON string, such as the source a Dynamic node lists. It’s null for projected nodes.
The entry, category, asset or other element this node links to. It’s null for nodes that don’t link to an element, and when the schema can’t read the element’s section, category group, volume, product type or site. Use an inline fragment such as ... on page_Entry to request the element’s own fields.
The ID of the element this node links to. It’s null for nodes that don’t link to an element.
Whether a Dynamic node generated this node when the menu was read, rather than an editor saving it in the menu. Projected nodes are always ProjectedNavigationNode types.
The handle of the menu this node belongs to.
The ID of the menu this node belongs to.
The name of the menu this node belongs to, as shown in the control panel.
A string that says whether this node opens in a new window. It’s "1" when it does and an empty string when it doesn’t, so test it as a truthy value rather than comparing it to true.
The node’s URL without the site’s base URL, such as about/team. It’s an empty string when the node has no URL.
The node one level up in the menu. It’s null for a top-level node.
The PHP class of this node’s type, such as verbb\navigation\nodetypes\Entry or verbb\navigation\nodetypes\Custom. Projected nodes return verbb\navigation\nodetypes\Dynamic.
The name of this node’s type as editors see it, such as “Entry” or “Custom URL”.
The node’s full URL, including its URL suffix. It’s null for nodes without a link, such as passive nodes.
The text an editor added to the end of this node’s URL, such as an anchor (#pricing) or a query string. It’s null when none is set.
This query requests the common fields for a two-level menu.
{
navigationNodes(menuHandle: "mainMenu", level: 1) {
id
title
url
typeLabel
newWindow
children {
id
title
url
}
}
}{
"data": {
"navigationNodes": [
{
"id": "102",
"title": "About",
"url": "https://example.com/about",
"typeLabel": "Entry",
"newWindow": "",
"children": [
{
"id": "103",
"title": "Our Team",
"url": "https://example.com/about/team"
}
]
}
]
}
}The [handle]_Node Type
Each menu the schema can read has its own node type, named after the menu’s handle, such as mainMenu_Node for Main Menu. It implements NodeInterface and adds the custom fields from that menu’s node field layout. Request those fields with an inline fragment.
In this example, Main Menu’s node field layout has a plain text field called badge and an Assets field called icon.
{
navigationNodes(menuHandle: "mainMenu", level: 1) {
title
url
... on mainMenu_Node {
badge
icon {
url
alt
}
}
}
}{
"data": {
"navigationNodes": [
{
"title": "Shop",
"url": "https://example.com/shop",
"badge": "New",
"icon": [
{
"url": "https://example.com/uploads/icons/bag.svg",
"alt": "Shopping bag"
}
]
}
]
}
}Custom fields also work as query arguments, the same way they do for entries.
The ProjectedNavigationNode Type
Nodes a Dynamic node generates when the menu is read use this type. It implements NodeInterface, but these nodes aren’t saved, so many fields have nothing to return. Projected Node explains how they’re built.
| Field | Returns |
|---|---|
id, uid | A generated identifier, unique within the menu. |
title, url, nodeUri | The title and URL of the element the node lists. |
siteId, siteHandle, language, uri | Values for the site the menu was read for. |
level, lft, rgt | The node’s position in the menu, beneath its Dynamic node. |
isProjected | Always true. |
elementId, element | The element the node lists, with element subject to the schema’s content permissions. |
menuId, menuHandle, menuName, typeLabel | Values from the Dynamic node that generated it. |
type | Always verbb\navigation\nodetypes\Dynamic. |
parent, children | The node’s parent and any nested projected children. |
customAttributes | Always an empty list. |
| Every other field | null, including classes, urlSuffix, newWindow, data, dateCreated, dateUpdated and structureId. |
Use __typename or isProjected when your frontend renders projected and saved nodes differently.
{
navigationNodes(menuHandle: "mainMenu", level: 1) {
title
children {
__typename
title
url
isProjected
}
}
}The NodeCustomAttribute Type
One extra HTML attribute on a node, returned by the customAttributes field.
The attribute’s name, such as data-track or aria-label.
The attribute’s value.
Menu Types
The [handle]_Menu Type
Each menu the schema can read has its own menu type, named after the menu’s handle, such as mainMenu_Menu. The [handle]_Menu query returns it. It includes Craft’s element fields, such as id, uid and siteHandle, and the custom fields from the menu’s own field layout, which you request directly by their handles. Navigation adds the following fields.
The menu’s handle, used to refer to the menu in Twig and GraphQL.
The menu’s name, as shown in the control panel.
{
mainMenu_Menu {
title
handle
menuHeading
}
}Context Types
The NavigationContext Type
The navigationContext query returns this type. It describes where the URL Craft is handling sits in a menu. Each field returns null or an empty list when no node in the menu matches that URL.
All the nodes that are active for the URL, meaning nodes that match it, nodes whose URL is a section of it, and nodes with an active descendant. Use it to highlight a whole branch rather than one link.
The nodes above the current node, from the top level down to its parent.
The current node’s ancestors followed by its siblings, in that order. Use it to build a sidebar that shows the path to the current page and the pages beside it.
The current node’s direct children.
The node that matches the URL. When several nodes match, it’s the deepest one.
All the nodes that match the URL, deepest first.
The handle of the menu the context was worked out for.
The current node’s parent. It’s null when the current node is at the top level or no node matches.
The nodes that share the current node’s parent, including the current node itself. When the current node is at the top level, these are the menu’s top-level nodes.
The NavigationMenuBreadcrumb Type
Each item in the navigationMenuBreadcrumbs list uses this type, from the top level down to the current node.
Whether this item’s node matches the URL Craft is handling. It’s true for the last item in the trail.
The node this item represents, for requesting fields the item doesn’t include, such as classes or element.
The title to show for this item.
The item’s URL. It’s null for nodes without a link.
{
navigationMenuBreadcrumbs(menuHandle: "mainMenu") {
title
url
current
node {
id
typeLabel
}
}
}