bit Bswup

Preparing the app for offline use, please wait...

0%

The Built-in Progress UI

Instead of writing a handler yourself, use the built-in splash/progress UI: the BswupProgress Razor component (the markup) plus bit-bswup.progress.js (the behavior). It registered the splash you saw when this site first installed.

Reference both in your host document:

html
<link rel="stylesheet" href="_content/Bit.Bswup/bit-bswup.progress.css" />
...
<script src="_content/Bit.Bswup/bit-bswup.js" ...></script>
<script src="_content/Bit.Bswup/bit-bswup.progress.js"></script>

Then render the component:

razor
<BswupProgress AutoReload="false" ShowAssets="true" HideApp="true" AutoHide="true" />

Component parameters

Each parameter maps to a data-bit-bswup-* attribute that the script reads at load time. The component emits no inline <script>, so it works under a strict Content-Security-Policy and when rendered by an interactive Blazor renderer.

ParameterDefaultDescription
AutoReloadtrueReload automatically when an update finishes. Set it to false to show the reload button and let the user accept the update instead.
ShowOnUpdatetrueDrive the splash during a background update - one downloading behind an already-installed, running app - as well as during a first install. Set it to false when the splash is a full-viewport take-over that should not paint over a live UI.
ShowLogsfalseLog lifecycle messages to the console.
ShowAssetsfalseList each downloaded asset inside the splash.
AppContainer#appSelector of the element to hide while installing (used with HideApp). An invalid selector is tolerated - only the hiding is skipped.
HideAppfalseHide the app container while the first install downloads.
AutoHidefalseHide the splash automatically when the download finishes.
Handler-Name of an additional custom handler invoked after the built-in handling, so you can layer your own behavior without replacing the UI. (Do not point it at bitBswupHandler itself - self-references are detected and ignored.)
ChildContent-Replaces the default splash markup with your own - see below.

Behavior worth knowing

  • The splash is painted for a background update as well as a first install, so the user sees an update being fetched. Set ShowOnUpdate="false" to make it first-install only, for a take-over splash that should not paint over a running app.
  • The update-ready button lives outside #bit-bswup so it can appear without revealing the splash: an update already staged at page load never produced a progress event to reveal it, and neither does one under ShowOnUpdate="false". Its appearance is announced through a role="status" region.
  • Clicks outside the splash content pass through the overlay, so an app force-started under a failure panel stays usable.
  • A failure panel with retry appears for fatal first-install errors; deterministic failures (an unparseable manifest, an integrity mismatch) hide the retry button since reloading would fail identically.
  • Runtime toggles are available via BitBswupProgress.config({ autoReload, showLogs, showAssets, hideApp, autoHide, showOnUpdate }).

Custom splash content

Pass ChildContent to replace the default splash markup. The component keeps initializing automatically, and the built-in behavior drives your markup through the documented element ids - include whichever you want driven:

Element idDriven as
bit-bswup-progress-barWidth + aria-valuenow set to the download percentage; the splash root also gets --bit-bswup-percent / --bit-bswup-percent-text CSS variables.
bit-bswup-percentText content set to NN%.
bit-bswup-assetsEach downloaded asset prepended as a list item.
bit-bswup-error (+ -message, -details, -retry)The failure panel for fatal first-install errors.
bit-bswup-reload / bit-bswup-reload-statusThe update-ready button and its screen-reader status region.
Don't render your own reload button
The update-ready button (#bit-bswup-reload) and its status region are always rendered by the component itself, outside the overlay, even with custom content - they are what an app running under AutoReload="false" relies on to surface a finished update. A custom splash should not render its own copy of those two; restyle them by id instead.

Standalone WebAssembly apps

In a standalone Blazor WebAssembly app the splash must exist before Blazor starts - on a first install, Blazor only boots after the download completes - so the BswupProgress component (which renders as part of the app) cannot paint the first-install splash. Hand-write the same markup in index.html instead; bit-bswup.progress.js self-initializes from the data-bit-bswup-* attributes exactly as it does for the component:

html
<div id="bit-bswup"
     data-bit-bswup-config="true"
     data-bit-bswup-auto-reload="false"
     data-bit-bswup-hide-app="true"
     data-bit-bswup-auto-hide="true"
     data-bit-bswup-handler="myExtraHandler">
    <div class="bit-bswup-container">
        <p class="bit-bswup-title">Installing the app</p>
        <div class="bit-bswup-progress">
            <div id="bit-bswup-progress-bar" role="progressbar" aria-label="Update download progress"
                 aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" style="width: 0%"></div>
        </div>
        <p id="bit-bswup-percent">0%</p>
        <div id="bit-bswup-error" class="bit-bswup-error" style="display: none;" role="alert">
            <p class="bit-bswup-error-title">Update failed to install</p>
            <p id="bit-bswup-error-message" class="bit-bswup-error-message"></p>
            <pre id="bit-bswup-error-details" class="bit-bswup-error-details"></pre>
            <button id="bit-bswup-error-retry" type="button">Retry</button>
        </div>
    </div>
</div>
<!-- OUTSIDE the overlay: -->
<button id="bit-bswup-reload" type="button" style="display: none;">Update ready - reload</button>
<span id="bit-bswup-reload-status" role="status" class="bit-bswup-visually-hidden"></span>
Two placement rules
Keep #bit-bswup-reload and its status region outside the #bit-bswup overlay (a finished background update must surface the button without revealing the splash), and give the button its own z-index if your app has fixed chrome in the top-right corner.

Prerendered Blazor Web Apps (like this site)

A Blazor Web App renders its host document (Components/App.razor) on the server, so the hand-written workaround above is unnecessary: drop <BswupProgress /> straight into App.razor, outside the interactive render-mode boundary. It is statically rendered, which puts its markup - and the data-bit-bswup-* configuration bit-bswup.progress.js reads - in the very first HTML the browser receives, before any script runs. This is what this site does; view source on any page for a complete working example.

html
<body>
    <!-- Statically rendered: present before blazor.web.js (and the app) start. -->
    <BswupProgress AutoReload="false" HideApp="true" AutoHide="true" AppContainer="#app" />

    <div id="app">
        <Routes @rendermode="renderMode" />
    </div>

    <script src="_framework/blazor.web.js" autostart="false"></script>
    <script src="_content/Bit.Bswup/bit-bswup.js" scope="/" sw="service-worker.js"></script>
    <script src="_content/Bit.Bswup/bit-bswup.progress.js"></script>
</body>