{"title":"Razor Islands","description":"Reference for the Razor Island system \u2014 interfaces, data attributes, JSON envelope, and lifecycle events","islands":{"content":"\u003Cheader class=\u0022transition-all mb-4 lg:mb-8\u0022\u003E\u003Ch1 class=\u0022font-display text-2xl lg:text-4xl font-bold tracking-tight text-base-900 dark:text-base-50\u0022\u003ERazor Islands\u003C/h1\u003E\u003C/header\u003E\n\n\u003Cmain class=\u0022prose dark:prose-invert dark:text-base-300 max-w-full prose-sm md:prose-base min-w-0 prose-headings:scroll-m-18 prose-headings:font-display prose-headings:text-base-900 dark:prose-headings:text-base-50\u0022\u003E\u003Cp\u003ERazor Islands add SPA navigation to static content sites. Each island is a named region of the page that\nupdates independently when the user navigates, while the surrounding layout stays in place. The first page\nload is always full static HTML; subsequent navigations fetch a JSON envelope and swap island contents.\u003C/p\u003E\n\u003Ch2 id=\u0022registration\u0022\u003ERegistration\u003C/h2\u003E\n\u003Cdiv class=\u0022code-highlight-wrapper not-prose\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-container\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-highlight\u0022\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-function roslyn-identifier\u0022\u003Eservices\u003C/span\u003E\u003Cspan class=\u0022hljs-operator roslyn-operator\u0022\u003E.\u003C/span\u003E\u003Cspan class=\u0022hljs-function roslyn-identifier\u0022\u003EAddContentEngineService\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E(\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E..\u003C/span\u003E\u003Cspan class=\u0022hljs-operator roslyn-operator\u0022\u003E.\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E)\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E    \u003Cspan class=\u0022hljs-operator roslyn-operator\u0022\u003E.\u003C/span\u003E\u003Cspan class=\u0022hljs-function roslyn-identifier\u0022\u003EWithMarkdownContentService\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E\u0026lt;\u003C/span\u003E\u003Cspan class=\u0022hljs-function roslyn-identifier\u0022\u003ETFrontMatter\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E\u0026gt;\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E(\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E..\u003C/span\u003E\u003Cspan class=\u0022hljs-operator roslyn-operator\u0022\u003E.\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E)\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E    \u003Cspan class=\u0022hljs-operator roslyn-operator\u0022\u003E.\u003C/span\u003E\u003Cspan class=\u0022hljs-function roslyn-identifier\u0022\u003EWithSpaNavigation\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E\u0026lt;\u003C/span\u003E\u003Cspan class=\u0022hljs-function roslyn-identifier\u0022\u003ETFrontMatter\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E\u0026gt;\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E(\u003C/span\u003E\u003Cspan class=\u0022hljs-variable roslyn-parameter-name\u0022\u003Espa\u003C/span\u003E \u003Cspan class=\u0022hljs-operator roslyn-operator\u0022\u003E=\u0026gt;\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E    \u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E{\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E        \u003Cspan class=\u0022hljs-variable roslyn-parameter-name\u0022\u003Espa\u003C/span\u003E\u003Cspan class=\u0022hljs-operator roslyn-operator\u0022\u003E.\u003C/span\u003E\u003Cspan class=\u0022hljs-function roslyn-identifier\u0022\u003EAddIsland\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E\u0026lt;\u003C/span\u003E\u003Cspan class=\u0022hljs-function roslyn-identifier\u0022\u003EMyContentIslandRenderer\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E\u0026gt;\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E(\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E)\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E;\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E        \u003Cspan class=\u0022hljs-variable roslyn-parameter-name\u0022\u003Espa\u003C/span\u003E\u003Cspan class=\u0022hljs-operator roslyn-operator\u0022\u003E.\u003C/span\u003E\u003Cspan class=\u0022hljs-function roslyn-identifier\u0022\u003EAddIsland\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E\u0026lt;\u003C/span\u003E\u003Cspan class=\u0022hljs-function roslyn-identifier\u0022\u003EMySidebarIslandRenderer\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E\u0026gt;\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E(\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E)\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E;\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E    \u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E}\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E)\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E;\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E  \u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-comment roslyn-comment\u0022\u003E// In the middleware pipeline:\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-function roslyn-identifier\u0022\u003Eapp\u003C/span\u003E\u003Cspan class=\u0022hljs-operator roslyn-operator\u0022\u003E.\u003C/span\u003E\u003Cspan class=\u0022hljs-function roslyn-identifier\u0022\u003EUseSpaNavigation\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E(\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E)\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E;\u003C/span\u003E\u003C/span\u003E\u003C/code\u003E\u003C/pre\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\n\u003Cp\u003E\u003Ccode\u003EWithSpaNavigation\u0026lt;TFrontMatter\u0026gt;()\u003C/code\u003E registers:\u003C/p\u003E\n\u003Ctable\u003E\n\u003Cthead\u003E\n\u003Ctr\u003E\n\u003Cth\u003EService\u003C/th\u003E\n\u003Cth\u003ELifetime\u003C/th\u003E\n\u003Cth\u003EPurpose\u003C/th\u003E\n\u003C/tr\u003E\n\u003C/thead\u003E\n\u003Ctbody\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003ESpaPageDataService\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003ETransient\u003C/td\u003E\n\u003Ctd\u003EResolves metadata from \u003Ccode\u003EPageToGenerate.Metadata\u003C/code\u003E across all content services and orchestrates island renderers into a \u003Ccode\u003ESpaPageEnvelope\u003C/code\u003E\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003EComponentRenderer\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EScoped\u003C/td\u003E\n\u003Ctd\u003EWraps Blazor\u0027s \u003Ccode\u003EHtmlRenderer\u003C/code\u003E for Razor-based renderers\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003ESpaNavigationContentService\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003ETransient\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003EIContentService\u003C/code\u003E that generates \u003Ccode\u003E_spa-data/*.json\u003C/code\u003E for all registered content services during static builds\u003C/td\u003E\n\u003C/tr\u003E\n\u003C/tbody\u003E\n\u003C/table\u003E\n\u003Cp\u003E\u003Ccode\u003EUseSpaNavigation()\u003C/code\u003E maps the endpoint that serves the JSON envelope for each page.\u003C/p\u003E\n\u003Ch2 id=\u0022ispaislandrenderer\u0022\u003EISpaIslandRenderer\u003C/h2\u003E\n\u003Cp\u003EThe core interface for producing HTML content for a named island.\u003C/p\u003E\n\u003Cdiv class=\u0022code-highlight-wrapper not-prose\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-container\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-highlight\u0022\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-keyword roslyn-keyword\u0022\u003Epublic\u003C/span\u003E \u003Cspan class=\u0022hljs-keyword roslyn-keyword\u0022\u003Einterface\u003C/span\u003E \u003Cspan class=\u0022hljs-type roslyn-interface-name\u0022\u003EISpaIslandRenderer\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E{\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E    \u003Cspan class=\u0022hljs-keyword roslyn-keyword\u0022\u003Estring\u003C/span\u003E \u003Cspan class=\u0022hljs-attr roslyn-property-name\u0022\u003EIslandName\u003C/span\u003E \u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E{\u003C/span\u003E \u003Cspan class=\u0022hljs-keyword roslyn-keyword\u0022\u003Eget\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E;\u003C/span\u003E \u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E}\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E    \u003Cspan class=\u0022hljs-function roslyn-identifier\u0022\u003ETask\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E\u0026lt;\u003C/span\u003E\u003Cspan class=\u0022hljs-keyword roslyn-keyword\u0022\u003Estring\u003C/span\u003E\u003Cspan class=\u0022hljs-operator roslyn-operator\u0022\u003E?\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E\u0026gt;\u003C/span\u003E \u003Cspan class=\u0022hljs-function roslyn-method-name\u0022\u003ERenderAsync\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E(\u003C/span\u003E\u003Cspan class=\u0022hljs-keyword roslyn-keyword\u0022\u003Estring\u003C/span\u003E \u003Cspan class=\u0022hljs-variable roslyn-parameter-name\u0022\u003Eurl\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E)\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E;\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E}\u003C/span\u003E\u003C/span\u003E\u003C/code\u003E\u003C/pre\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\n\u003Ctable\u003E\n\u003Cthead\u003E\n\u003Ctr\u003E\n\u003Cth\u003EMember\u003C/th\u003E\n\u003Cth\u003EDescription\u003C/th\u003E\n\u003C/tr\u003E\n\u003C/thead\u003E\n\u003Ctbody\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003EIslandName\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EMust match a \u003Ccode\u003Edata-spa-island\u003C/code\u003E attribute in the layout. Multiple renderers for the same name are allowed \u2014 only the last registered one runs.\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003ERenderAsync\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EReceives the content page URL (e.g. \u003Ccode\u003E\u0022/\u0022\u003C/code\u003E, \u003Ccode\u003E\u0022/pasta-carbonara\u0022\u003C/code\u003E). Return \u003Ccode\u003Enull\u003C/code\u003E to omit this island from the envelope.\u003C/td\u003E\n\u003C/tr\u003E\n\u003C/tbody\u003E\n\u003C/table\u003E\n\u003Ch2 id=\u0022razorislandrenderertcomponent\u0022\u003ERazorIslandRenderer\u0026lt;TComponent\u0026gt;\u003C/h2\u003E\n\u003Cp\u003EAbstract base class that renders a Blazor component to a string via \u003Ccode\u003EComponentRenderer\u003C/code\u003E. Subclasses provide\nthe island name and build a parameter dictionary; the base class handles the \u003Ccode\u003EHtmlRenderer\u003C/code\u003E ceremony.\u003C/p\u003E\n\u003Cdiv class=\u0022code-highlight-wrapper not-prose\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-container\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-highlight\u0022\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-keyword roslyn-keyword\u0022\u003Epublic\u003C/span\u003E \u003Cspan class=\u0022hljs-keyword roslyn-keyword\u0022\u003Eabstract\u003C/span\u003E \u003Cspan class=\u0022hljs-keyword roslyn-keyword\u0022\u003Eclass\u003C/span\u003E \u003Cspan class=\u0022hljs-type roslyn-class-name\u0022\u003ERazorIslandRenderer\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E\u0026lt;\u003C/span\u003E\u003Cspan class=\u0022hljs-type roslyn-type-parameter-name\u0022\u003ETComponent\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E\u0026gt;\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E(\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E    \u003Cspan class=\u0022hljs-function roslyn-identifier\u0022\u003EComponentRenderer\u003C/span\u003E \u003Cspan class=\u0022hljs-variable roslyn-parameter-name\u0022\u003Erenderer\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E)\u003C/span\u003E \u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E:\u003C/span\u003E \u003Cspan class=\u0022hljs-function roslyn-identifier\u0022\u003EISpaIslandRenderer\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E    \u003Cspan class=\u0022hljs-keyword roslyn-keyword\u0022\u003Ewhere\u003C/span\u003E \u003Cspan class=\u0022hljs-type roslyn-type-parameter-name\u0022\u003ETComponent\u003C/span\u003E \u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E:\u003C/span\u003E \u003Cspan class=\u0022hljs-function roslyn-identifier\u0022\u003EIComponent\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E{\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E    \u003Cspan class=\u0022hljs-keyword roslyn-keyword\u0022\u003Epublic\u003C/span\u003E \u003Cspan class=\u0022hljs-keyword roslyn-keyword\u0022\u003Eabstract\u003C/span\u003E \u003Cspan class=\u0022hljs-keyword roslyn-keyword\u0022\u003Estring\u003C/span\u003E \u003Cspan class=\u0022hljs-attr roslyn-property-name\u0022\u003EIslandName\u003C/span\u003E \u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E{\u003C/span\u003E \u003Cspan class=\u0022hljs-keyword roslyn-keyword\u0022\u003Eget\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E;\u003C/span\u003E \u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E}\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E    \u003Cspan class=\u0022hljs-keyword roslyn-keyword\u0022\u003Eprotected\u003C/span\u003E \u003Cspan class=\u0022hljs-keyword roslyn-keyword\u0022\u003Eabstract\u003C/span\u003E \u003Cspan class=\u0022hljs-function roslyn-identifier\u0022\u003ETask\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E\u0026lt;\u003C/span\u003E\u003Cspan class=\u0022hljs-function roslyn-identifier\u0022\u003EIDictionary\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E\u0026lt;\u003C/span\u003E\u003Cspan class=\u0022hljs-keyword roslyn-keyword\u0022\u003Estring\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E,\u003C/span\u003E \u003Cspan class=\u0022hljs-keyword roslyn-keyword\u0022\u003Eobject\u003C/span\u003E\u003Cspan class=\u0022hljs-operator roslyn-operator\u0022\u003E?\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E\u0026gt;\u003C/span\u003E\u003Cspan class=\u0022hljs-operator roslyn-operator\u0022\u003E?\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E\u0026gt;\u003C/span\u003E \u003Cspan class=\u0022hljs-function roslyn-method-name\u0022\u003EBuildParametersAsync\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E(\u003C/span\u003E\u003Cspan class=\u0022hljs-keyword roslyn-keyword\u0022\u003Estring\u003C/span\u003E \u003Cspan class=\u0022hljs-variable roslyn-parameter-name\u0022\u003Eurl\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E)\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E;\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-punctuation roslyn-punctuation\u0022\u003E}\u003C/span\u003E\u003C/span\u003E\u003C/code\u003E\u003C/pre\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\n\u003Cp\u003E\u003Ccode\u003EBuildParametersAsync\u003C/code\u003E returns \u003Ccode\u003Enull\u003C/code\u003E to skip the island for that page, or a dictionary of component\nparameters keyed by \u003Ccode\u003Enameof(Component.Property)\u003C/code\u003E.\u003C/p\u003E\n\u003Cdiv class=\u0022markdown-alert markdown-alert-note\u0022\u003E\n\u003Cp class=\u0022markdown-alert-title\u0022\u003E\u003Csvg viewBox=\u00220 0 16 16\u0022 version=\u00221.1\u0022 width=\u002216\u0022 height=\u002216\u0022 aria-hidden=\u0022true\u0022\u003E\u003Cpath d=\u0022M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z\u0022\u003E\u003C/path\u003E\u003C/svg\u003ENote\u003C/p\u003E\n\u003Cp\u003EComponents rendered via \u003Ccode\u003ERazorIslandRenderer\u003C/code\u003E support \u003Ccode\u003E@inject\u003C/code\u003E for DI services but cannot use\nJavaScript interop, \u003Ccode\u003ENavigationManager\u003C/code\u003E, or other browser-dependent APIs.\u003C/p\u003E\n\u003C/div\u003E\n\u003Ch2 id=\u0022page-metadata\u0022\u003EPage Metadata\u003C/h2\u003E\n\u003Cp\u003EThe \u003Ccode\u003Etitle\u003C/code\u003E and \u003Ccode\u003Edescription\u003C/code\u003E fields in the JSON envelope are resolved automatically from\n\u003Ccode\u003EPageToGenerate.Metadata\u003C/code\u003E across all registered \u003Ccode\u003EIContentService\u003C/code\u003E instances. Any content service\nthat populates \u003Ccode\u003EMetadata.Title\u003C/code\u003E on its pages will participate in SPA navigation \u2014 no additional\nregistration is needed.\u003C/p\u003E\n\u003Ch2 id=\u0022spapageenvelope\u0022\u003ESpaPageEnvelope\u003C/h2\u003E\n\u003Cp\u003EThe JSON payload returned for each page.\u003C/p\u003E\n\u003Cdiv class=\u0022code-highlight-wrapper not-prose\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-container\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-highlight\u0022\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E{\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E  \u003Cspan class=\u0022hljs-punctuation\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Etitle\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E:\u003C/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003EPasta Carbonara\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E,\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E  \u003Cspan class=\u0022hljs-punctuation\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Edescription\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E:\u003C/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003EClassic Roman carbonara with guanciale and pecorino\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E,\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E  \u003Cspan class=\u0022hljs-punctuation\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Eislands\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E:\u003C/span\u003E \u003Cspan class=\u0022hljs-punctuation\u0022\u003E{\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E    \u003Cspan class=\u0022hljs-punctuation\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Econtent\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E:\u003C/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0026lt;header\u0026gt;\u2026\u0026lt;/header\u0026gt;\u0026lt;div class=\u003C/span\u003E\u003Cspan class=\u0022hljs-regexp\u0022\u003E\\\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003Eprose\u003C/span\u003E\u003Cspan class=\u0022hljs-regexp\u0022\u003E\\\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0026gt;\u2026\u0026lt;/div\u0026gt;\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E,\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E    \u003Cspan class=\u0022hljs-punctuation\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Erecipe-info\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E:\u003C/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0026lt;div class=\u003C/span\u003E\u003Cspan class=\u0022hljs-regexp\u0022\u003E\\\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003Erounded-lg\u003C/span\u003E\u003Cspan class=\u0022hljs-regexp\u0022\u003E\\\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0026gt;\u2026\u0026lt;/div\u0026gt;\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E  \u003Cspan class=\u0022hljs-punctuation\u0022\u003E}\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E}\u003C/span\u003E\u003C/span\u003E\u003C/code\u003E\u003C/pre\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\n\u003Ctable\u003E\n\u003Cthead\u003E\n\u003Ctr\u003E\n\u003Cth\u003EField\u003C/th\u003E\n\u003Cth\u003EType\u003C/th\u003E\n\u003Cth\u003EDescription\u003C/th\u003E\n\u003C/tr\u003E\n\u003C/thead\u003E\n\u003Ctbody\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003Etitle\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003Estring\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EPage title \u2014 used by the SPA engine to set \u003Ccode\u003Edocument.title\u003C/code\u003E\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003Edescription\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003Estring?\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EPage description \u2014 updates \u003Ccode\u003E\u0026lt;meta name=\u0022description\u0022\u0026gt;\u003C/code\u003E\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003Eislands\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003Eobject\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EMap of island name \u2192 HTML string. Keys match \u003Ccode\u003Edata-spa-island\u003C/code\u003E attributes.\u003C/td\u003E\n\u003C/tr\u003E\n\u003C/tbody\u003E\n\u003C/table\u003E\n\u003Ch2 id=\u0022data-attributes\u0022\u003EData Attributes\u003C/h2\u003E\n\u003Cp\u003EAdd these to layout elements to make them Razor Islands.\u003C/p\u003E\n\u003Ch3 id=\u0022data-spa-island\u0022\u003Edata-spa-island\u003C/h3\u003E\n\u003Cp\u003EMarks an element as an island. The value is the island name.\u003C/p\u003E\n\u003Cdiv class=\u0022code-highlight-wrapper not-prose\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-container\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-highlight\u0022\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003Earticle\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E \u003C/span\u003E\u003Cspan class=\u0022hljs-attr\u0022\u003Edata-spa-island\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E=\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003Econtent\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026gt;\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E    @Body\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;/\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003Earticle\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026gt;\u003C/span\u003E\u003C/span\u003E\u003C/code\u003E\u003C/pre\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\u003Ch3 id=\u0022data-spa-loading\u0022\u003Edata-spa-loading\u003C/h3\u003E\n\u003Cp\u003EControls what happens to the island while a slow fetch is in progress.\u003C/p\u003E\n\u003Ctable\u003E\n\u003Cthead\u003E\n\u003Ctr\u003E\n\u003Cth\u003EValue\u003C/th\u003E\n\u003Cth\u003EBehaviour\u003C/th\u003E\n\u003C/tr\u003E\n\u003C/thead\u003E\n\u003Ctbody\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003E\u0022skeleton\u0022\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EShows a shimmer placeholder (or a custom \u003Ccode\u003E\u0026lt;template\u0026gt;\u003C/code\u003E, see below)\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003E\u0022clear\u0022\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EEmpties the island immediately\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003E\u0022keep\u0022\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003ELeaves previous content in place until new data arrives (default)\u003C/td\u003E\n\u003C/tr\u003E\n\u003C/tbody\u003E\n\u003C/table\u003E\n\u003Cdiv class=\u0022code-highlight-wrapper not-prose\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-container\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-highlight\u0022\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003Earticle\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E \u003C/span\u003E\u003Cspan class=\u0022hljs-attr\u0022\u003Edata-spa-island\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E=\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003Econtent\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E \u003C/span\u003E\u003Cspan class=\u0022hljs-attr\u0022\u003Edata-spa-loading\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E=\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003Eskeleton\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026gt;\u003C/span\u003E\u003C/span\u003E\u003C/code\u003E\u003C/pre\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\u003Ch3 id=\u0022custom-skeleton-templates\u0022\u003ECustom Skeleton Templates\u003C/h3\u003E\n\u003Cp\u003EProvide a \u003Ccode\u003E\u0026lt;template\u0026gt;\u003C/code\u003E element with \u003Ccode\u003Edata-spa-skeleton-for\u003C/code\u003E matching the island name:\u003C/p\u003E\n\u003Cdiv class=\u0022code-highlight-wrapper not-prose\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-container\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-highlight\u0022\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003Etemplate\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E \u003C/span\u003E\u003Cspan class=\u0022hljs-attr\u0022\u003Edata-spa-skeleton-for\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E=\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003Econtent\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026gt;\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E    \u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003Ediv\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E \u003C/span\u003E\u003Cspan class=\u0022hljs-attr\u0022\u003Eclass\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E=\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003Eanimate-pulse space-y-4\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026gt;\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E        \u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003Ediv\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E \u003C/span\u003E\u003Cspan class=\u0022hljs-attr\u0022\u003Eclass\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E=\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003Eh-8 bg-neutral-200 rounded w-3/4\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026gt;\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;/\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003Ediv\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026gt;\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E        \u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003Ediv\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E \u003C/span\u003E\u003Cspan class=\u0022hljs-attr\u0022\u003Eclass\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E=\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003Eh-4 bg-neutral-200 rounded w-full\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026gt;\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;/\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003Ediv\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026gt;\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E        \u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003Ediv\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E \u003C/span\u003E\u003Cspan class=\u0022hljs-attr\u0022\u003Eclass\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E=\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003Eh-4 bg-neutral-200 rounded w-5/6\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026gt;\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;/\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003Ediv\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026gt;\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E    \u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;/\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003Ediv\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026gt;\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;/\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003Etemplate\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026gt;\u003C/span\u003E\u003C/span\u003E\u003C/code\u003E\u003C/pre\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\n\u003Cp\u003EIf no custom template exists, the engine shows a default shimmer skeleton.\u003C/p\u003E\n\u003Ch2 id=\u0022configuration-via-html-attributes\u0022\u003EConfiguration via \u0026lt;html\u0026gt; Attributes\u003C/h2\u003E\n\u003Cp\u003EThe SPA engine reads configuration from \u003Ccode\u003Edata-*\u003C/code\u003E attributes on the \u003Ccode\u003E\u0026lt;html\u0026gt;\u003C/code\u003E element.\u003C/p\u003E\n\u003Ctable\u003E\n\u003Cthead\u003E\n\u003Ctr\u003E\n\u003Cth\u003EAttribute\u003C/th\u003E\n\u003Cth\u003EDefault\u003C/th\u003E\n\u003Cth\u003EPurpose\u003C/th\u003E\n\u003C/tr\u003E\n\u003C/thead\u003E\n\u003Ctbody\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003Edata-base-url\u003C/code\u003E (on \u003Ccode\u003E\u0026lt;body\u0026gt;\u003C/code\u003E)\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003E\u0022\u0022\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EBase URL prefix for subdirectory deployments (set automatically by \u003Ccode\u003EBaseUrlRewritingMiddleware\u003C/code\u003E)\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003Edata-spa-data-path\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003E\u0022/_spa-data\u0022\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EURL prefix for page data JSON files\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003Edata-spa-skeleton-delay\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003E\u0022100\u0022\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EMilliseconds before showing the skeleton (fast fetches skip it)\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003Edata-spa-min-skeleton\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003E\u0022250\u0022\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EMinimum milliseconds to show the skeleton once visible\u003C/td\u003E\n\u003C/tr\u003E\n\u003C/tbody\u003E\n\u003C/table\u003E\n\u003Ch2 id=\u0022lifecycle-events\u0022\u003ELifecycle Events\u003C/h2\u003E\n\u003Cp\u003EThe SPA engine dispatches custom events on \u003Ccode\u003Edocument\u003C/code\u003E.\u003C/p\u003E\n\u003Ch3 id=\u0022spabefore-navigate\u0022\u003Espa:before-navigate\u003C/h3\u003E\n\u003Cp\u003EFires before the fetch starts. Use it to clear transient UI state.\u003C/p\u003E\n\u003Cdiv class=\u0022code-highlight-wrapper not-prose\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-container\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-highlight\u0022\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-variable\u0022\u003Edocument\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E.\u003C/span\u003E\u003Cspan class=\u0022hljs-title\u0022\u003EaddEventListener\u003C/span\u003E(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003Espa:before-navigate\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E,\u003C/span\u003E \u003Cspan class=\u0022hljs-punctuation\u0022\u003E(\u003C/span\u003E\u003Cspan class=\u0022hljs-variable\u0022\u003Ee\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E)\u003C/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003E=\u0026gt;\u003C/span\u003E \u003Cspan class=\u0022hljs-punctuation\u0022\u003E{\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E    \u003Cspan class=\u0022hljs-keyword\u0022\u003Econst\u003C/span\u003E \u003Cspan class=\u0022hljs-punctuation\u0022\u003E{\u003C/span\u003E \u003Cspan class=\u0022hljs-literal\u0022\u003Eurl\u003C/span\u003E \u003Cspan class=\u0022hljs-punctuation\u0022\u003E}\u003C/span\u003E \u003Cspan class=\u0022hljs-operator\u0022\u003E=\u003C/span\u003E \u003Cspan class=\u0022hljs-variable\u0022\u003Ee\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E.\u003C/span\u003E\u003Cspan class=\u0022hljs-variable\u0022\u003Edetail\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E;\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E    \u003C/span\u003E\u003Cspan class=\u0022hljs-comment\u0022\u003E//\u003C/span\u003E\u003Cspan class=\u0022hljs-comment\u0022\u003E Clear tooltips, close modals, etc.\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E}\u003C/span\u003E)\u003Cspan class=\u0022hljs-punctuation\u0022\u003E;\u003C/span\u003E\u003C/span\u003E\u003C/code\u003E\u003C/pre\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\u003Ch3 id=\u0022spacommit\u0022\u003Espa:commit\u003C/h3\u003E\n\u003Cp\u003EFires after new island content is injected into the DOM. Use it to reinitialise interactive features.\u003C/p\u003E\n\u003Cdiv class=\u0022code-highlight-wrapper not-prose\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-container\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-highlight\u0022\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-variable\u0022\u003Edocument\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E.\u003C/span\u003E\u003Cspan class=\u0022hljs-title\u0022\u003EaddEventListener\u003C/span\u003E(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003Espa:commit\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E,\u003C/span\u003E \u003Cspan class=\u0022hljs-punctuation\u0022\u003E(\u003C/span\u003E\u003Cspan class=\u0022hljs-variable\u0022\u003Ee\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E)\u003C/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003E=\u0026gt;\u003C/span\u003E \u003Cspan class=\u0022hljs-punctuation\u0022\u003E{\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E    \u003Cspan class=\u0022hljs-keyword\u0022\u003Econst\u003C/span\u003E \u003Cspan class=\u0022hljs-punctuation\u0022\u003E{\u003C/span\u003E \u003Cspan class=\u0022hljs-literal\u0022\u003Eurl\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E,\u003C/span\u003E \u003Cspan class=\u0022hljs-literal\u0022\u003Edata\u003C/span\u003E \u003Cspan class=\u0022hljs-punctuation\u0022\u003E}\u003C/span\u003E \u003Cspan class=\u0022hljs-operator\u0022\u003E=\u003C/span\u003E \u003Cspan class=\u0022hljs-variable\u0022\u003Ee\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E.\u003C/span\u003E\u003Cspan class=\u0022hljs-variable\u0022\u003Edetail\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E;\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E    \u003C/span\u003E\u003Cspan class=\u0022hljs-comment\u0022\u003E//\u003C/span\u003E\u003Cspan class=\u0022hljs-comment\u0022\u003E Re-highlight code, rebuild outline, update active nav links, etc.\u003C/span\u003E\u003C/span\u003E\n\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E}\u003C/span\u003E)\u003Cspan class=\u0022hljs-punctuation\u0022\u003E;\u003C/span\u003E\u003C/span\u003E\u003C/code\u003E\u003C/pre\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\n\u003Ctable\u003E\n\u003Cthead\u003E\n\u003Ctr\u003E\n\u003Cth\u003EDetail field\u003C/th\u003E\n\u003Cth\u003EType\u003C/th\u003E\n\u003Cth\u003EDescription\u003C/th\u003E\n\u003C/tr\u003E\n\u003C/thead\u003E\n\u003Ctbody\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003Eurl\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003EURL\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EThe navigated URL\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003Edata\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003Eobject\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EThe full \u003Ccode\u003ESpaPageEnvelope\u003C/code\u003E (title, description, islands)\u003C/td\u003E\n\u003C/tr\u003E\n\u003C/tbody\u003E\n\u003C/table\u003E\n\u003Ch2 id=\u0022spanavigationbuilder\u0022\u003ESpaNavigationBuilder\u003C/h2\u003E\n\u003Cp\u003EFluent builder passed to the \u003Ccode\u003EWithSpaNavigation\u0026lt;T\u0026gt;()\u003C/code\u003E configure callback.\u003C/p\u003E\n\u003Ctable\u003E\n\u003Cthead\u003E\n\u003Ctr\u003E\n\u003Cth\u003EMethod\u003C/th\u003E\n\u003Cth\u003EDescription\u003C/th\u003E\n\u003C/tr\u003E\n\u003C/thead\u003E\n\u003Ctbody\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003EAddIsland\u0026lt;TRenderer\u0026gt;()\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003ERegisters an \u003Ccode\u003EISpaIslandRenderer\u003C/code\u003E implementation\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003EWithDataPath(string)\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EChanges the data endpoint path (default \u003Ccode\u003E\u0022/_spa-data\u0022\u003C/code\u003E)\u003C/td\u003E\n\u003C/tr\u003E\n\u003C/tbody\u003E\n\u003C/table\u003E\n\u003Ch2 id=\u0022scripts\u0022\u003EScripts\u003C/h2\u003E\n\u003Cp\u003EInclude in your \u003Ccode\u003EApp.razor\u003C/code\u003E after \u003Ccode\u003Escripts.js\u003C/code\u003E:\u003C/p\u003E\n\u003Cdiv class=\u0022code-highlight-wrapper not-prose\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-container\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-highlight\u0022\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003Escript\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E \u003C/span\u003E\u003Cspan class=\u0022hljs-attr\u0022\u003Esrc\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E=\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E/_content/MyLittleContentEngine.UI/spa-engine.js\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E \u003C/span\u003E\u003Cspan class=\u0022hljs-attr\u0022\u003Edefer\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026gt;\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E/\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003Escript\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026gt;\u003C/span\u003E\u003C/span\u003E\u003C/code\u003E\u003C/pre\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\n\u003Cp\u003EThe engine activates automatically \u2014 no initialisation call needed. It discovers islands from\n\u003Ccode\u003Edata-spa-island\u003C/code\u003E attributes, intercepts same-origin link clicks, and handles history, view transitions,\nand scroll position.\u003C/p\u003E\n\u003C/main\u003E\u003Cdiv class=\u0022flex my-12 border-t border-base-200 dark:border-base-700 pt-4 lg:pt-8\u0022\u003E\u003Cdiv class=\u0022flex flex-col items-start  gap-3\u0022\u003E\u003Ca class=\u0022inline-flex gap-0.5 justify-center overflow-hidden text-sm font-medium font-display transition rounded-xl bg-base-200 pt-1.5 pb-1 px-3 lg:pt-2 lg:pb.15 lg:px-4 hover:bg-base-300/75 dark:bg-base-800/40 text-base-800 dark:text-base-400 ring-1 dark:ring-inset ring-base-300/75 dark:ring-base-800 dark:hover:bg-base-800 dark:hover:text-base-300\u0022 aria-label=\u0022Previous: MonorailCSS Configuration\u0022 href=\u0022/MyLittleContentEngine/reference/monorail-css-configuration/\u0022\u003E\u003Cspan class=\u0022-ml-1 rotate-180\u0022\u003E\u003Csvg viewBox=\u00220 0 20 20\u0022 fill=\u0022none\u0022 aria-hidden=\u0022true\u0022 class=\u0022mt-0.5 h-5 w-5\u0022\u003E\u003Cpath stroke=\u0022currentColor\u0022 stroke-linecap=\u0022round\u0022 stroke-linejoin=\u0022round\u0022 d=\u0022m11.5 6.5 3 3.5m0 0-3 3.5m3-3.5h-9\u0022\u003E\u003C/path\u003E\u003C/svg\u003E\u003C/span\u003E Previous\u003C/a\u003E\n            \u003Ca tabindex=\u0022-1\u0022 aria-hidden=\u0022true\u0022 class=\u0022text-sm lg:text-base font-semibold text-base-700 transition hover:text-base-600 dark:text-base-400 dark:hover:text-base-300\u0022 href=\u0022/MyLittleContentEngine/reference/monorail-css-configuration/\u0022\u003EMonorailCSS Configuration\u003C/a\u003E\u003C/div\u003E\u003C/div\u003E"}}