Zap Studio

Splash Screen

Display a branded loading screen while your Local.ts app initializes.

Local.ts includes a splash screen that displays while your app initializes. This creates a polished first impression and prevents users from seeing an empty window during startup.

How It Works

The splash screen uses Tauri's multi-window feature:

  1. On launch — The splash screen window shows immediately while the main window stays hidden
  2. During initialization — Your app loads settings, connects to the database, and sets up stores
  3. When ready — The splash closes and the main window appears

This ensures users see a branded loading experience instead of a blank window.

Window Configuration

The windows are defined in src-tauri/tauri.conf.json:

{
  "windows": [
    {
      "title": "Local.ts",
      "label": "main",
      "visible": false,
      "width": 1280,
      "height": 720,
      "center": true
    },
    {
      "title": "Loading...",
      "label": "splashscreen",
      "url": "splash.html",
      "width": 1280,
      "height": 720,
      "center": true,
      "decorations": false
    }
  ]
}

Note that main has visible: false so it stays hidden until initialization completes.

Closing the Splash Screen

The close_splashscreen command in Rust closes the splash and shows the main window:

#[tauri::command]
pub fn close_splashscreen(window: tauri::Window) {
    if let Some(splash) = window.get_webview_window("splashscreen") {
        let _ = splash.close();
    }
    if let Some(main) = window.get_webview_window("main") {
        let _ = main.show();
        let _ = main.set_focus();
    }
}

This is called from the React StoreInitializer component after all initialization completes:

useEffect(() => {
  const init = async () => {
    try {
      await initializeSettings();
      initializeTheme();
      setIsInitialized(true);

      // Close splash screen and show main window
      await invoke("close_splashscreen");
    } catch (err) {
      console.error("Failed to initialize:", err);
      setError(err);

      // Still close splash on error to show error UI
      await invoke("close_splashscreen").catch(console.error);
    }
  };

  init();
}, []);

Customizing the Splash Screen

To customize the splash screen, modify splash.html located at your project root. Here is the default template:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="stylesheet" href="/src/styles/globals.css" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Loading...</title>
  </head>
  <body>
    <div class="container flex flex-col items-center justify-center h-screen">
      <h1 class="text-2xl font-bold text-foreground">Local.ts</h1>
      <p class="mt-2 text-muted-foreground">
        A starter kit for building local-first applications
      </p>
    </div>
  </body>
</html>

Changing Splash Window Size

In tauri.conf.json:

{
  "label": "splashscreen",
  "url": "splash.html",
  "width": 400,
  "height": 300,
  "center": true,
  "decorations": false
}

Setting decorations: false removes the window title bar for a cleaner look.

Error Handling with Retry

If initialization fails (for example, a database connection error), the StoreInitializer component displays an error screen with a retry button instead of leaving users stuck on the splash screen.

The component tracks error state and provides a retry mechanism:

const [error, setError] = useState<Error | null>(null);

const handleRetry = async () => {
  setError(null);
  setIsInitialized(false);

  try {
    await initializeSettings();
    initializeTheme();
    setIsInitialized(true);
  } catch (err) {
    console.error("Retry failed:", err);
    setError(err instanceof Error ? err : new Error("Unknown error"));
  }
};

if (error) {
  return <InitializationError error={error} onRetry={handleRetry} />;
}

The error UI component shows a clear message and retry button:

function InitializationError({ error, onRetry }: InitializationErrorProps) {
  return (
    <div className="flex h-screen flex-col items-center justify-center gap-4 p-6">
      <div className="text-center">
        <h1 className="text-2xl font-bold text-destructive">
          Initialization Error
        </h1>
        <p className="mt-2 text-muted-foreground">
          Failed to load application settings
        </p>
        <p className="mt-1 text-sm text-muted-foreground">{error.message}</p>
      </div>
      <button
        type="button"
        onClick={onRetry}
        className="rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90"
      >
        Retry
      </button>
    </div>
  );
}

This ensures users always have a path forward, even when something goes wrong during app startup.

Removing the Splash Screen

If you prefer to show the main window immediately:

  1. Update tauri.conf.json:

      "windows": [
        {
          "title": "Local.ts",
          "label": "main",
    -     "visible": false,
    +     "visible": true,
          "width": 1280,
          "height": 720
        },
    -   {
    -     "title": "Loading...",
    -     "label": "splashscreen",
    -     "url": "splash.html",
    -     "width": 1280,
    -     "height": 720
    -   }
      ]
  2. Delete splash.html

  3. Remove the window command — Delete src-tauri/src/commands/window.rs

  4. Update commands module — Remove the export from src-tauri/src/commands/mod.rs

  5. Unregister the command from src-tauri/src/lib.rs:

    .invoke_handler(tauri::generate_handler![
        commands::settings::get_app_settings,
        commands::settings::update_app_settings,
        commands::settings::set_tray_visible,
    -   commands::window::close_splashscreen,
    ])
  6. Remove the invoke call from src/components/store-initializer.tsx:

    - await invoke("close_splashscreen");

Learn More

Learn more about Tauri splash screens by checking the official documentation.

Edit on GitHub

Last updated on

On this page