--- title: Behaviour and fallbacks description: How Luma takes over your listings and hands them back, what it does to make pages fast, the switches for each of those, browser support and known limitations. slug: luma/behaviour docKind: concept hub: luigisbox-ai --- ## Taking over a listing On a search or category page Luma decides, per page, whether the listing is its own: 1. **Hold.** Your listing is hidden but keeps its space, and the height Luma's listing had on this URL last time is reserved, so nothing below moves. 2. **Show.** Luma's listing replaces yours in one frame, after the fonts its text uses have loaded (at most 800 ms). 3. **Or release.** Your own listing is shown and the page stays yours until the next visit. Luma releases the page when: - the URL is not one the configuration can express — a later page of yours, a parameter it does not map, - the category is empty or cannot be resolved, - a request fails, - nothing has rendered within `holdTimeoutMs` (4 seconds by default). After two failures in a row in one browser session, Luma stops holding that kind of page and renders only once results are in, so an outage never blanks your listing on every page view. Without the [early-hold snippet](/luma/installing/#the-early-hold-snippet), or when Luma starts after your listing has painted, your listing shows first and Luma's replaces it. ## Navigation - **Links to products are ordinary links.** A click on one is a normal page load of your product page. Opening it in a new tab, with a modifier key or a middle click, works as on any link. - **Filtering and sorting change the URL without a page load.** Each change adds one history entry, so Back returns to the previous state of the listing. "Show more" adds none. - **Your router stays in charge.** On a single-page app whose router Luma can find — Vue Router, the Next.js pages router — Luma changes the URL through it, so the router knows the current URL. Elsewhere Luma adds a plain history entry. It never edits your entries. - **A new search on the search page renders in place.** Submitting your search form while on the search page adds a history entry and re-renders the listing, without a page load. On any other page, your form submits as usual. `search.inPlaceQuery: false` makes every search a page load. ## Speed | What | Switch | Default | |---|---|---| | A new query on the search page renders without a page load | `search.inPlaceQuery` | On | | Search results are fetched once the typed phrase settles, so Enter shows them at once | `search.prefetchWhileTyping` | On | | A filter, sort or chip is fetched when the shopper hovers, touches or focuses it | `_global.prefetchFilters` | On | | The next page is fetched as the shopper nears the end of the list | `prefetchNextPage` | On | | Back from a product restores the listing at the tile the shopper followed | `restoreOnBack` | On | | Off-screen tiles skip rendering work | `contentVisibility` | Off | | Product pages are prerendered on hover | `_global.speculation` | `prerender` | Each one falls back to what the page would do without it. Nothing is fetched ahead when the shopper's device is offline, has data-saving mode turned on, or is on a 2G connection. Luma's code is loaded in parts. The base every page loads is at most 14 kB compressed. Each widget's code, templates and styles load separately, only on pages where that widget runs; their size depends on your integration, and an integration with many templates has larger ones. [`yarn luma footprint`](/luma/tools/#checking-an-integration) reports what each kind of page loads. ### Speeding up navigation With `_global.speculation` set to `prerender` (the default), Chrome and Edge prerender a product page when the shopper hovers its link in a Luma widget — about 200 ms of hover, or a press on touch — and show it at once on the click. The browser keeps two at a time. A prerendered page costs your server a page render, whether or not the shopper follows it, and your product page's scripts run in it before it is shown. Analytics that do not wait for the page to be shown count a page view. Set `prefetch` to fetch only the HTML, or `false` to turn it off. ## Accessibility Luma's built-in widgets meet WCAG 2.2 AA, as required by EN 301 549 and the European Accessibility Act: - The search input gets combobox semantics while the autocomplete dropdown is open, and the dropdown is fully usable from the keyboard. - The filter drawer and the phone autocomplete sheet keep focus inside while open. They, the dropdown and the recommender popup close with Escape. - A listing is marked busy while it renders, and result counts are announced. - A high-contrast mode follows the visitor's operating-system setting. `_global.contrastToggle: true` adds a switch for it at the start of every listing. Template overrides take on part of that responsibility — see [Templates](/luma/templates/#accessibility). ## Browser support Luma targets [Baseline Widely available](https://web.dev/baseline): Chrome and Edge 107, Firefox 104, Safari 16 and later. Nothing is polyfilled. Newer features are used where the browser has them: | Feature | Without it | |---|---| | Popover API | No autocomplete dropdown and no recommender popup; your own suggestions remain | | Navigation API | URL changes are detected another way | | Speculation Rules (Chrome, Edge) | Product pages are not prerendered | On a browser older than the target, or a plain-HTTP page, Luma does not start and your site keeps its own search, listings and recommendations. ## Known limitations - **Autocomplete needs the Popover API.** Safari before 17 and Firefox before 125 keep your own suggestions. - **The first page view is not held.** The early-hold snippet works from rules stored on earlier views, so a browser's first page view can show your listing briefly. - **A search shown in place fires no page view of yours.** Luma's own [`lumaPages()`](/luma/analytics/#triggers) counts it. If your own analytics need one per search, set `search.inPlaceQuery: false`. - **Analytics loads after the page has.** See [Analytics limitations](/luma/analytics/#limitations). - **Fetching ahead costs requests.** A result fetched ahead of a click — while typing, on hover over a filter, for the next page — is an API request like any other, and counts as one whether or not the shopper uses it. - **Some routers cannot be reached.** Where Luma cannot find your router — a Vue Router 4 app that is not discoverable, Angular in production — the router can overwrite Luma's history entry or show a stale query in its search box. Set `search.inPlaceQuery: false` on such a site. - **No numbered pages.** Listings grow with "show more"; a URL cannot point at page 5. ## See also - [Installing on your site](/luma/installing/) - [Tools and debugging](/luma/tools/) — measuring what Luma costs your pages