Scrolling & Navigation (Desktop)
Scroll containment
- Decide, per view, exactly which element scrolls — usually the content pane, while the header, sidebar, and toolbar stay fixed. Never let the whole window body scroll if the shell has a fixed header/sidebar; that causes navigation chrome to visually detach from the content as it moves.
- A scrollable region should be visually obvious before the user even touches it where it matters (a subtle top/bottom fade or shadow when there's more content above/below, rather than requiring the user to scroll blindly to discover more exists).
Scrollbar styling
- Custom-styled scrollbars should still feel native — slim, low-contrast track, a thumb that darkens slightly on hover, no bright accent-colored scrollbar thumbs (a strong "web app pretending to be native" tell). Avoid replacing the scrollbar with something so thin or low-contrast it's hard to grab and drag.
- Don't hide scrollbars entirely on desktop the way some mobile patterns do — desktop users expect a persistent or hover-revealed scrollbar they can grab directly, not just momentum-scroll with no visible track.
- Keep the scrollbar's appearance consistent across every scrollable region in the app — a custom-styled scrollbar in one panel and the raw OS default in another is an inconsistency that's easy to spot.
Pagination vs. infinite scroll vs. virtualization
| Pattern | Best for |
|---|---|
| Pagination (page numbers or prev/next) | Data the user needs to reference by position ("page 3 had the one I wanted"), or where jumping to a specific point matters |
| Infinite scroll / load-more | Feeds and discovery-oriented lists where position doesn't matter and continuous browsing is the point |
| Virtualized long list, no pagination needed | Very long but bounded lists (a file browser, a project list) where the user wants to see everything, scroll fluidly, and search/filter rather than page through — see desktop-ui-spacing-sizing for virtualization |
Infinite scroll without virtualization on a long list is a common performance mistake — the DOM keeps growing as more loads in, which gets expensive fast on constrained hardware. If using infinite scroll, virtualize it.
Keyboard navigation
Desktop users expect full keyboard access, not just mouse support layered with a few shortcuts as an afterthought:
- Tab order must follow visual/logical reading order, not DOM/declaration order if they've diverged.
- Arrow keys should move focus within a related group (a list, a menu, a tab set) rather than only moving between the group's outer boundary and the rest of the page.
- Enter/Space activates the focused control; Escape closes the nearest dismissible layer (a menu, a popover, a modal) without navigating away from the underlying view.
- A visible focus indicator (see
desktop-ui-buttons-controls) must be present for every interactive element — this is not optional polish, it's how keyboard users track where they are. - If the app has a command-palette / quick-switcher pattern, treat it as a first-class navigation method, not a hidden power-user Easter egg — surface its shortcut somewhere discoverable (a search bar hint, a menu item).
Breadcrumbs and location awareness
- Use breadcrumbs when the user can be several levels deep in a real hierarchy (nested folders, nested project structure) and needs both "where am I" and "jump back up N levels" in one control.
- Don't use breadcrumbs for flat, single-level navigation — that's what the sidebar/tab active-state already communicates (see
desktop-ui-layout-navigation); a breadcrumb with one or two static segments is decorative, not functional. - Each breadcrumb segment except the current one should be clickable and jump directly there — a non-interactive breadcrumb trail is just a label, not navigation.
Review format
| Before | After | Why |
|---|---|---|
| Whole window scrolls, sidebar drifts along with content | Content pane scrolls independently, sidebar/header pinned | Fixed chrome that moves with scroll reads as a layout bug |
| Infinite-scrolling list mounts every loaded item permanently | Same list, virtualized so only visible rows are mounted | Prevents growing memory/DOM cost as more content loads, important on modest hardware |
| Custom scrollbar styled bright accent-color and very thick | Slim, low-contrast track with a subtly-darkening thumb on hover | Keeps the custom scrollbar feeling native rather than like a styled web widget |