# Nested roots > A group inside a group — the nearest root wins, so an inner list navigates by its own keys while the list around it keeps its. Composite widgets nest: a menu with a row of reactions along the top, a settings list with a colour grid inside one of its rows. `data-keyrove-root` marks a group, and the root keyrove navigates by is the _nearest_ one above the focused element — so an inner group can sit inside an outer one and keep its own keys, columns, and page size. walk the menu, and from _Reply_ steps into the reaction row. Inside it, move between reactions and Escape returns to the menu. The inner group is a root with its own attributes; nothing else about it is special — the same `data-keyrove-item` marks its items. ```html ``` ```ts document .querySelector('#message-actions') .addEventListener('keydown', (e) => keyRove(e)); ``` One listener, on the outer list. The inner group needs none of its own: the keydown bubbles up to that listener, and `keyRove` resolves the root from the event's _target_ rather than from the element the listener sits on. That is also why the outer list here carries no `data-keyrove-root` — it is the listener's element, which keyrove falls back to. Move the listener further up (to a panel, or to `document`) and the outer group needs the attribute too. ## The nearest root wins Root attributes are read off the group focus is currently in, and nothing is inherited across the boundary: ```html
Row
Row
``` PageDown moves five rows in the panel and two grid rows in the grid; move a cell inside the grid and nothing outside it. Home and End follow the same rule: while focus is in the grid they land on its first and last cell, not on the panel's. ### The outer group still sees the inner items `data-keyrove-item` is matched anywhere below the root, nested groups included. The outer group's order therefore runs straight _through_ the inner one: in the demo, from _Reply_ lands on the last reaction rather than skipping the row. That is usually what you want — the outer group's keys reach the inner one instead of it being reachable by Tab alone — but an inner group is not hidden from the list around it, and there is no attribute that hides it. If a group should be unreachable that way, put it outside the outer root. ## Getting back out Once focus is inside the inner group, no key reaches the outer one. A key the inner root does not bind — in the reaction row above — does nothing at all: keyrove leaves it to the browser rather than passing it on to the group outside. Leaving is yours to wire, and there are two ways to do it. Tab is the first, and it needs no code beyond [roving tabindex](/docs/examples/roving-tabindex). keyrove never binds Tab, so the browser's own focus order is always a way out of a nested group — roving tabindex just makes it a tidy one. Give each group its own roving items and each becomes a single tab stop, so Tab moves group to group and Shift+Tab back — the arrangement the [ARIA authoring practices](https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/) describe for composite widgets. The second is a key of your own. The demo above binds Escape on the reaction row, handing focus to the item beside it: ```ts reactions.addEventListener('keydown', (e) => { if (e.code !== 'Escape') return; reactions.nextElementSibling.focus(); }); ``` keyrove never acts on Escape, so nothing collides — the same holds for any code the roots involved have not bound. Which also means the exit key is yours to choose on the same terms as the navigation keys. ## Nesting, or two roots side by side Nest only when the inner group genuinely sits inside the outer one's flow. Groups that are merely on the same page do not need to be nested at all: marking each of them `data-keyrove-root` under one delegated listener keeps them fully independent, with no group's items in another's order. See [several groups, one listener](/docs/installation#several-groups-one-listener).