Zum Inhalt springen
    WingoUI
    KomponentenVorlagenDokuPreiseKI-AgentenBlogChangelogKontakt
    1. Startseite
    2. Blog
    3. Mobile UI mit React
    4. Next.js PWA ohne next-pwa: Offline-Seite und App Shell
    Read in English
    1. Blog
    2. Mobile UI mit React
    3. Next.js PWA ohne next-pwa: Offline-Seite und App Shell
    Mobile UI mit React
    Mobile UI mit React

    Next.js PWA ohne next-pwa: Offline-Seite und App Shell

    SR
    Serban Rusu · Gründer von Wingo UI
    5. Nov. 2026 · 12 Min. Lesezeit

    Auf dieser Seite

    0%
    1. Was braucht eine Next.js PWA im Jahr 2026?
    2. Wie fügst du im App Router ein Web App Manifest hinzu?
    3. Brauchst du für eine Next.js 16 PWA noch next-pwa?
    4. Wie zeigst du in einer Next.js PWA eine Offline-Seite?
      1. 1. Eine eigenständige Offline-Seite
      2. 2. Der Service Worker
      3. 3. Registrier ihn aus einer Client-Komponente
      4. 4. Teste ihn
    5. Was passiert mit clientseitigen Navigationen, wenn das Netz wegfällt?
    6. Wie fügst du einer Next.js PWA einen Install Prompt hinzu?
    7. Wie fühlt sich eine Next.js PWA auf dem Smartphone nativ an?
      1. Blende reine Browser-UI in der installierten App aus
      2. Starte mit einem fertigen Home-Screen
    8. Was solltest du vor dem Release der PWA prüfen?
    9. Was solltest du als Nächstes bauen?
    10. Häufige Fragen
      1. Funktioniert next-pwa mit Next.js 16?
      2. Braucht eine Next.js PWA einen Service Worker, um installierbar zu sein?
      3. Warum erscheint meine Offline-Seite in Next.js ohne Styles?
      4. Wie teste ich einen Service Worker in Next.js lokal?
      5. Gibt es ein Next.js PWA Template mit App Shell?

    Kurz gesagt

    Eine Next.js PWA mit dem App Router braucht vier eigene Dateien: app/manifest.ts mit Name, Icons und standalone-Display, eine eigenständige public/offline.html, eine kleine public/sw.js, die diese Seite ausliefert, wenn ein Seitenaufruf scheitert, und eine Client-Komponente, die den Worker registriert. Lass next-pwa auf Next.js 16 weg: Es ist ein Webpack-Plugin, und next build läuft inzwischen mit Turbopack, also schreibst du den Worker selbst und steigst erst auf Serwist um, wenn du gecachte Routen und Assets brauchst. Setz im viewport-Export viewportFit auf cover und ergänze dann einen Install Prompt und eine App Shell, deren Top Bar und Bottom Tabs die Safe Areas freihalten.

    Veröffentlicht am 5. Nov. 2026

    Eine Next.js PWA ist eine ganz normale App-Router-App mit ein paar zusätzlichen Dateien: einem Web App Manifest, Icons, einem Service Worker und einem Layout, das auch ohne die Bedienleisten des Browsers gut aussieht. Der offizielle Guide deckt das Manifest und Push-Benachrichtigungen ab. Viele Tutorials installieren danach next-pwa, ein Webpack-Plugin, in ein Framework, das inzwischen standardmäßig mit Turbopack baut. Dieses Tutorial nimmt für Next.js 16 einen schlankeren Weg: einen selbst geschriebenen Worker, der eine Offline-Seite zeigt, einen Install Prompt und eine App Shell mit Top Bar und Bottom Tabs, die Notch und Home-Indikator freihalten.

    Was braucht eine Next.js PWA im Jahr 2026?

    Weniger, als ältere Guides vermuten lassen. Hier ist die komplette Liste für eine Next.js PWA mit dem App Router, jeweils mit dem, was dir das Teil bringt:

    TeilDateiFür die Installation nötig?Was es dir bringt
    Web App Manifestapp/manifest.tsjaName, Icons, standalone-Display, Start-URL
    Iconspublic/icon-192.png, public/icon-512.png, app/apple-icon.pngjaIcons auf dem Home-Bildschirm und im App-Umschalter
    HTTPSdein Hostingja (localhost ist ausgenommen)einen sicheren Kontext für den Worker
    Service Workerpublic/sw.js + eine Register-Komponenteneineine Offline-Seite, Push, das automatische Install-Event von Chrome
    Viewport und Themeexport const viewport in app/layout.tsxneinDarstellung bis an den Rand, eine farbige Statusleiste
    Install Prompteine Client-Komponente im Root-Layoutneindeinen eigenen Installieren-Button und die Schritte fürs iPhone
    App Shellapp/(app)/layout.tsxneinTop Bar, Bottom Tabs, Safe Areas

    Die Regeln zur Installierbarkeit pro Browser, auch warum Chrome sein Install-Event beim ersten Besuch zurückhalten kann, stehen in unserem Guide zum React PWA Install Prompt. Dieser Beitrag wiederholt sie deshalb nicht.

    Wie fügst du im App Router ein Web App Manifest hinzu?

    Über die Dateikonvention manifest. Eine app/manifest.ts, die eine Funktion als Default exportiert, wird unter /manifest.webmanifest ausgeliefert und automatisch im <head> jeder Seite verlinkt:

    ts
    // app/manifest.ts
    import type { MetadataRoute } from "next";
    export default function manifest(): MetadataRoute.Manifest {
    return {
    id: "/",
    name: "Northwind CRM",
    short_name: "Northwind",
    description: "Kunden, Angebote und Rechnungen auf deinem Smartphone.",
    start_url: "/",
    scope: "/",
    display: "standalone",
    background_color: "#ffffff",
    theme_color: "#ffffff",
    icons: [
    { src: "/icon-192.png", sizes: "192x192", type: "image/png" },
    { src: "/icon-512.png", sizes: "512x512", type: "image/png" },
    { src: "/icon-maskable-512.png", sizes: "512x512", type: "image/png", purpose: "maskable" },
    ],
    };
    }

    Leg die drei PNGs in public/. Beim maskierbaren Icon bleibt das Logo innerhalb der mittleren 80%, damit Android es zu einem Kreis oder einem Squircle zuschneiden kann. Fürs iPhone legst du eine app/apple-icon.png mit 180x180 neben das Layout; Next.js macht daraus den Link apple-touch-icon.

    Dann sagst du dem Browser, wie die installierte App dargestellt werden soll. viewport und metadata sind im App Router getrennte Exporte, und beide funktionieren nur in Server Components:

    tsx
    // app/layout.tsx
    import type { Metadata, Viewport } from "next";
    import type { ReactNode } from "react";
    import { RegisterServiceWorker } from "./register-sw";
    import "./globals.css";
    export const metadata: Metadata = {
    title: "Northwind CRM",
    appleWebApp: { capable: true, title: "Northwind", statusBarStyle: "black-translucent" },
    };
    export const viewport: Viewport = {
    // die seite darf unter notch und home-indikator zeichnen; die shell gleicht das mit padding wieder aus
    viewportFit: "cover",
    themeColor: [
    { media: "(prefers-color-scheme: light)", color: "#ffffff" },
    { media: "(prefers-color-scheme: dark)", color: "#0b0b0f" },
    ],
    };
    export default function RootLayout({ children }: { children: ReactNode }) {
    return (
    <html lang="de">
    <body>
    {children}
    <RegisterServiceWorker />
    </body>
    </html>
    );
    }

    viewportFit: "cover" ist wichtiger, als es aussieht. Ohne diese Einstellung zeigt iOS die Seite mit Rändern oben und unten, und env(safe-area-inset-*) bleibt 0. Komponenten, die die Safe Areas per Padding freihalten, laufen dann ins Leere. Mit der Einstellung läuft die Seite unter der Statusleiste und dem Home-Indikator durch, und Header und Tab Bar müssen diesen Platz wieder hinzufügen. Genau das macht die Shell weiter unten.

    Ein Haken beim iPhone: statusBarStyle: "black-translucent" sorgt dafür, dass die installierte App unter der Statusleiste zeichnen darf, lässt Uhrzeit und Akkuanzeige aber weiß. Gib der Top Bar im Light Mode deshalb eine ausreichend dunkle Füllung, oder nimm "default" für eine undurchsichtige Statusleiste über der Seite. Der obere Inset ist dann einfach 0.

    Brauchst du für eine Next.js 16 PWA noch next-pwa?

    Nein. Die letzte Version des ursprünglichen Plugins next-pwa (opens in a new tab), 5.6.0, ist im August 2022 erschienen, und der gepflegte Fork @ducanh2912/next-pwa (opens in a new tab) hat zuletzt im September 2024 die Version 10.2.9 veröffentlicht (npm-Registry, geprüft am 5. November 2026). Beide hängen sich in Webpack ein, während Next.js 16 next dev und next build mit Turbopack ausführt, solange du nicht --webpack übergibst. Laut Upgrade-Guide für Next.js 16 (opens in a new tab) schlägt next build fehl, wenn es eine Webpack-Konfiguration findet, und auch ein Plugin, das eine hinzufügt, zählt dazu. Eine Next.js 16 PWA auf Basis von next-pwa bleibt also entweder mit --webpack bei Webpack oder wird mit next build --turbopack, das die Konfiguration ignoriert, ohne generierten Worker ausgeliefert.

    Zwei Optionen funktionieren mit Turbopack:

    • Ein selbst geschriebener Worker für eine Offline-Seite und Push. Das ist eine einzige Datei in public/, ohne Build-Schritt und ohne Abhängigkeit. Den baut dieser Beitrag.
    • Serwist (opens in a new tab), wenn du Routen vorab cachen und Assets mit Strategien im Stil von Workbox cachen willst. Das Paket @serwist/turbopack (9.5.13, 4. Oktober 2026) liefert den Worker über einen Route Handler aus, der mit createSerwistRoute gebaut wird, kompiliert app/sw.ts mit esbuild und legt einen SerwistProvider um den Baum. Auch der Next.js-Guide zu PWAs (opens in a new tab) verweist für vollständiges Offline-Caching auf Serwist.

    Fang mit dem selbst geschriebenen Worker an. Steig erst an dem Tag auf Serwist um, an dem du gecachte Daten-Screens brauchst, nicht früher, denn jedes gecachte Asset ist eine Version, die du irgendwann wieder ablaufen lassen musst.

    Wie zeigst du in einer Next.js PWA eine Offline-Seite?

    Fang gescheiterte Seitenaufrufe im Worker ab und beantworte sie mit einer Seite, die du bei der Installation gecacht hast. Das ist das web.dev-Rezept für eine Offline-Fallback-Seite (opens in a new tab), angepasst an Next.js. Es ist das schlankste Next.js PWA Offline-Setup, das sich trotzdem wie eine App anfühlt statt wie der Dinosaurier des Browsers.

    1. Eine eigenständige Offline-Seite

    Mach die Offline-Seite nicht zu einer Next.js-Route. Ihr CSS und JavaScript liegen in gehashten Dateien unter /_next/static, die dein Worker nie gecacht hat, also würde sie offline als HTML ohne Styles laden. Schreib stattdessen einfaches HTML mit Inline-Styles:

    html
    <!-- public/offline.html -->
    <!doctype html>
    <html lang="de">
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
    <title>Du bist offline</title>
    <style>
    :root { color-scheme: light dark; --bg: #ffffff; --fg: #0b0b0f; --muted: #5b5b66; }
    @media (prefers-color-scheme: dark) { :root { --bg: #0b0b0f; --fg: #f5f5f7; --muted: #a1a1aa; } }
    body { margin: 0; min-height: 100dvh; display: grid; place-items: center; background: var(--bg); color: var(--fg);
    font: 16px/1.5 system-ui, sans-serif; padding: env(safe-area-inset-top) 24px env(safe-area-inset-bottom); }
    main { max-width: 22rem; text-align: center; }
    p { color: var(--muted); }
    button { min-height: 44px; padding: 0 20px; border: 0; border-radius: 12px; background: var(--fg); color: var(--bg);
    font: inherit; font-weight: 600; touch-action: manipulation; }
    </style>
    </head>
    <body>
    <main>
    <h1>Du bist offline</h1>
    <p>Northwind braucht eine Verbindung, um diese Seite zu laden. Sobald du wieder online bist, lädt sie von selbst neu.</p>
    <button type="button" onclick="location.reload()">Erneut versuchen</button>
    </main>
    <script>
    // lädt von selbst neu, sobald die verbindung zurück ist
    addEventListener("online", () => location.reload());
    </script>
    </body>
    </html>

    2. Der Service Worker

    js
    // public/sw.js
    const CACHE = "offline-v1";
    const OFFLINE_URL = "/offline.html";
    self.addEventListener("install", (event) => {
    // cache: "reload" umgeht den http-cache, die seite kommt also frisch vom server
    event.waitUntil(caches.open(CACHE).then((cache) => cache.add(new Request(OFFLINE_URL, { cache: "reload" }))));
    self.skipWaiting();
    });
    self.addEventListener("activate", (event) => {
    event.waitUntil(
    (async () => {
    if (self.registration.navigationPreload) await self.registration.navigationPreload.enable();
    const keys = await caches.keys();
    await Promise.all(keys.filter((key) => key !== CACHE).map((key) => caches.delete(key)));
    await self.clients.claim();
    })(),
    );
    });
    self.addEventListener("fetch", (event) => {
    // nur komplette seitenaufrufe; rsc-payloads, bilder und api-aufrufe gehen direkt ans netz
    if (event.request.mode !== "navigate") return;
    event.respondWith(
    (async () => {
    try {
    const preloaded = await event.preloadResponse;
    if (preloaded) return preloaded;
    return await fetch(event.request);
    } catch {
    // ein netzwerkfehler, kein 404 oder 500: die kommen weiterhin bei der seite an
    const cache = await caches.open(CACHE);
    return (await cache.match(OFFLINE_URL)) ?? Response.error();
    }
    })(),
    );
    });

    skipWaiting() und clients.claim() sind hier unbedenklich, weil dieser Worker keinen App-Code ausliefert. Sobald ein Worker deine JavaScript-Chunks cacht, kann ein neuer Worker, der unter einem offenen Tab aktiv wird, alte und neue Dateien mischen, und dann brauchst du stattdessen einen Hinweis „Update verfügbar“. Erhöh CACHE auf offline-v2, sobald sich offline.html ändert; der activate-Schritt löscht den alten Cache.

    3. Registrier ihn aus einer Client-Komponente

    tsx
    // app/register-sw.tsx
    "use client";
    import { useEffect } from "react";
    export function RegisterServiceWorker() {
    useEffect(() => {
    // dev baut ständig neu; teste den worker mit next build && next start
    if (process.env.NODE_ENV !== "production" || !("serviceWorker" in navigator)) return;
    navigator.serviceWorker.register("/sw.js", { scope: "/", updateViaCache: "none" }).catch(() => {});
    }, []);
    return null;
    }

    updateViaCache: "none" sorgt dafür, dass die Update-Prüfung bei Navigationen sw.js vom Server holt statt aus dem HTTP-Cache. Sichere das mit einem Header ab, damit auch CDNs keinen alten Worker vorhalten:

    ts
    // next.config.ts
    import type { NextConfig } from "next";
    const nextConfig: NextConfig = {
    async headers() {
    return [
    {
    source: "/sw.js",
    headers: [
    { key: "Cache-Control", value: "no-cache, no-store, must-revalidate" },
    { key: "Content-Security-Policy", value: "default-src 'self'; script-src 'self'" },
    ],
    },
    ];
    },
    };
    export default nextConfig;

    4. Teste ihn

    Führ next build && next start aus und öffne http://localhost:3000. localhost ist ein sicherer Kontext, du brauchst also kein Zertifikat. In den Chrome DevTools listet Application das Manifest und den aktiven Worker auf. Stell das Network-Panel auf Offline und lad neu: Statt der Fehlerseite des Browsers bekommst du deine eigene Seite.

    Was passiert mit clientseitigen Navigationen, wenn das Netz wegfällt?

    Sie scheitern wie jede andere Anfrage, denn der Worker oben sieht nur komplette Seitenaufrufe. Ein Tipp auf einen <Link> holt per fetch() eine Payload für React Server Components, keine Navigationsanfrage, also lässt der Worker sie zum Netz durch. Next.js 16 hat für diese Ebene eine Lösung, die noch als experimentell markiert ist: Mit experimental.useOffline: true in next.config.ts bleibt eine gescheiterte Navigation, ein Prefetch oder eine Server Action ausstehend und wird wiederholt, sobald die Verbindung zurück ist, und der Hook useOffline() aus next/offline sagt deiner UI, dass sie offline ist. Der Guide zum Offline-Support (opens in a new tab) zeigt darauf aufbauend ein Banner im Root-Layout. Betrachte das vorerst als nettes Extra und behalte den Worker als Sicherheitsnetz, denn ein experimentelles Flag kann sich zwischen Minor-Versionen ändern.

    Wie fügst du einer Next.js PWA einen Install Prompt hinzu?

    Binde die Komponente im Root-Layout ein, denn Chrome feuert beforeinstallprompt früh im Seitenaufbau, und eine Komponente, die erst später auf einer einzelnen Route mountet, kann das Event verpassen. Alle Details, von beforeinstallprompt über das Teilen-Menü auf dem iPhone bis zu der Frage, wann du besser nicht fragst, steht in React PWA Install Prompt für Chrome, Edge und iPhone. Die Kurzfassung mit unserem Install Prompt:

    tsx
    // in app/layout.tsx, neben <RegisterServiceWorker />
    import { InstallPrompt } from "@/components/ui/install-prompt";
    <InstallPrompt
    appName="Northwind CRM"
    appIcon="/icon-192.png"
    description="Öffne sie direkt vom Home-Bildschirm, auch offline."
    />

    In Chrome und Edge zeigt er den Installationsdialog des Browsers, auf dem iPhone die Schritte für „Zum Home-Bildschirm“. In der installierten App und in In-App-Browsern bleibt er verborgen, und ein Wegklicken merkt er sich standardmäßig 14 Tage lang. Auf dem Smartphone sitzt er über der Bottom Tab Bar aus dem nächsten Abschnitt, weil er deren --bottom-bar-offset ausliest. Die Offline-Seite aus dem vorigen Abschnitt macht „auch offline“ zu einem ehrlichen Versprechen.

    Wie fühlt sich eine Next.js PWA auf dem Smartphone nativ an?

    Gib der installierten App ihre eigenen Bedienleisten. Im Modus standalone gibt es keine Adressleiste und keinen Zurück-Button, also muss die App einen Header, einen Weg zurück und eine Hauptnavigation in Reichweite des Daumens mitbringen. Auf dem Smartphone heißt das: eine Top Bar und eine Bottom Tab Bar, beide mit Abstand für die Safe Areas, die du mit viewportFit: "cover" geöffnet hast.

    Die App Shell erledigt das als ein einziges Layout: Sidebar und Top Bar auf dem Desktop, eine Drawer-Navigation und eine Bottom Tab Bar unter 768px. Zieh die Demo unten auf Smartphone-Breite zusammen oder öffne sie auf deinem Smartphone und wechsle unten die Tabs:

    Dieselbe Shell auf Desktop und Smartphone: Mach das Fenster schmaler als 768px, dann wird die Sidebar zu einer Drawer-Navigation hinter dem Menü-Button, mit Tabs am unteren Rand.
    $ npx wingo-ui@latest add app-shell
    ProDoku: App Shell

    Installier sie mit npx wingo-ui@latest add app-shell; das kopiert auch Sidebar, Topbar und Bottom Tab Bar mit, die sie importiert. Dann machst du sie zum Layout der Routen für angemeldete Nutzer. Zuerst ein Provider, damit jeder Tab und jeder Sidebar-Link über next/link gerendert wird:

    tsx
    // app/providers.tsx
    "use client";
    import Link from "next/link";
    import type { ReactNode } from "react";
    import { usePathname, useRouter } from "next/navigation";
    import { LinkProvider } from "@/lib/navigation";
    export function Providers({ children }: { children: ReactNode }) {
    const router = useRouter();
    return (
    <LinkProvider component={Link} currentPath={usePathname()} navigate={router.push}>
    {children}
    </LinkProvider>
    );
    }

    Pack {children} im Root-Layout in <Providers> und bau dann die Shell:

    tsx
    // app/(app)/layout.tsx
    import type { ReactNode } from "react";
    import { FileText, House, Inbox, Settings, Users } from "lucide-react";
    import { AppShell } from "@/components/ui/app-shell";
    import type { SidebarNavGroup } from "@/components/ui/sidebar";
    import { Topbar } from "@/components/ui/topbar";
    import type { NavItem } from "@/lib/navigation";
    const nav: SidebarNavGroup[] = [
    {
    items: [
    { label: "Start", href: "/", icon: <House /> },
    { label: "Posteingang", href: "/inbox", icon: <Inbox />, badge: 4 },
    ],
    },
    {
    label: "Vertrieb",
    items: [
    { label: "Kunden", href: "/clients", icon: <Users /> },
    { label: "Rechnungen", href: "/invoices", icon: <FileText /> },
    ],
    },
    { label: "Konto", items: [{ label: "Einstellungen", href: "/settings", icon: <Settings /> }] },
    ];
    // vier tabs: die wichtigsten ziele auf dem smartphone
    const tabs: NavItem[] = [
    { label: "Start", href: "/", icon: <House /> },
    { label: "Kunden", href: "/clients", icon: <Users /> },
    { label: "Posteingang", href: "/inbox", icon: <Inbox />, badge: 4 },
    { label: "Einstellungen", href: "/settings", icon: <Settings /> },
    ];
    export default function AppLayout({ children }: { children: ReactNode }) {
    return (
    <AppShell nav={nav} topbar={<Topbar title="Northwind" />} tabs={tabs}>
    {children}
    </AppShell>
    );
    }

    Drei Details sorgen dafür, dass sie sich installiert anfühlt und nicht wie eine eingebettete Webseite:

    • Safe Areas. Die Topbar rechnet env(safe-area-inset-top) als Padding ein, die Bottom Tab Bar env(safe-area-inset-bottom), beides standardmäßig aktiv (safeArea). Unser Beitrag zu Tailwind Safe Area Insets deckt den Rest der Seite ab.
    • Echte Viewport-Höhe. Die Shell bemisst sich mit dvh statt vh, also endet eine kurze Seite am sichtbaren unteren Rand und nicht hinter der Toolbar von Safari. Die Hintergründe stehen in 100vh auf dem Smartphone und dvh in Tailwind.
    • Scrollen im Fenster. Mit dem Standard scroll="window" funktioniert die Wiederherstellung der Scrollposition durch den Router weiter, und die fixierte Tab Bar schreibt --bottom-bar-offset, damit schwebende Buttons ihr ausweichen.

    Blende reine Browser-UI in der installierten App aus

    Ein Marketing-Footer oder ein Link „App holen“ wirkt in der App selbst seltsam. Ergänz in app/globals.css eine Variante für den Display-Modus in Tailwind v4:

    css
    @custom-variant standalone (@media (display-mode: standalone));

    Dann entfernt className="standalone:hidden" ein Element nur in der installierten App, und standalone:pb-4 kann Platz hinzufügen, der nur dort zählt. Es ist CSS, also stimmt es schon beim ersten Paint, ohne Flackern bei der Hydration.

    Starte mit einem fertigen Home-Screen

    Für eine Consumer-App ist der Block Mobile App Home ein kompletter erster Screen auf Basis derselben Tab Bar: ein großer Titel, der beim Scrollen in die Leiste schrumpft, Suche, Stories, Schnellaktionen, Feed-Tabs und Pull to Refresh. Scroll ihn, zieh oben nach unten und wechsle die Feed-Tabs:

    Ein Marktplatz-Home-Screen, wie ihn eine installierte PWA zeigen würde: Scroll, damit der Titel schrumpft, zieh nach unten zum Aktualisieren und tipp unten auf die Tabs.
    $ npx wingo-ui@latest add mobile-app-home
    ProDoku: Mobile App Home

    Mit der Prop desktop="full" streckt er sich auf dem Tablet über die volle Breite, statt eine zentrierte Spalte mit 440px zu behalten. Das passt zu einer installierten App auf dem iPad.

    Was solltest du vor dem Release der PWA prüfen?

    Sechs Checks, wo möglich auf echten Geräten, denn die DevTools zeigen dir weder die Notch noch das Icon im Launcher noch den Flugmodus:

    1. Manifest. In den DevTools zeigt Application, dann Manifest keine Fehler, und beide Icon-Größen laden.
    2. Offline. Installier die App, schalte den Flugmodus ein und öffne sie: Du siehst offline.html, und sie lädt neu, sobald die Verbindung zurück ist.
    3. iPhone. Füg sie in Safari zum Home-Bildschirm hinzu. Der Text in der Statusleiste ist über deiner Top Bar lesbar, nichts liegt unter der Notch, und die Tab Bar hält Abstand zum Home-Indikator.
    4. Android. Installier sie aus Chrome, prüf das maskierbare Icon im Launcher und dreh das Smartphone einmal.
    5. Updates. Ändere offline.html, erhöh CACHE, deploye und öffne die App zweimal: Die neue Seite erscheint, und die DevTools listen einen einzigen Cache.
    6. Desktop. Installier sie aus Chrome oder Edge; die Shell sollte im eigenen Fenster das Layout mit Sidebar zeigen.

    Wenn du eigentlich nach einem Nextjs PWA Template gesucht hast, lass diese Checkliste darüber laufen, bevor du es übernimmst. Schritt 3 ist der, den dir ein Desktop-Browser nicht abnehmen kann.

    Was solltest du als Nächstes bauen?

    Liefer zuerst die vier Dateien aus: app/manifest.ts, public/offline.html, public/sw.js und die Register-Komponente. Sie sind reines Next.js, kostenlos und geben dir eine installierbare App mit einem ehrlichen Offline-Zustand. Für die Schicht der installierten App kopiert npx wingo-ui@latest add app-shell install-prompt die Shell, die Bottom Tabs und das Installationsbanner als Quellcode in dein Projekt; sie gehören zu Wingo UI Pro ($8 im Monat, $80 im Jahr oder $150 einmalig). Mehr Muster für Apps, die man mit einer Hand hält, findest du im Pillar-Beitrag zu Mobile-first React-Komponenten und in der Kategorie Mobile UI in React, und React Native vs PWA hilft dir, falls du noch abwägst, ob das Web reicht.

    Komponenten in diesem Artikel

    • Install Prompt

      A React PWA install prompt: the browser's install dialog in Chrome and Edge, and an Add to Home Screen guide on iPhone and Mac.

      Pro
    • App Shell

      A React app shell for admin layouts: a collapsible, resizable sidebar, a top bar and the page, with a drawer and a tab bar on phones.

      Pro
    • Bottom Tab Bar

      A React bottom tab bar for phones: 3 to 5 tabs at the thumb with an animated pill, badges, a raised center action and hide on scroll.

      Pro
    • Mobile App Home

      A React mobile app home screen for a marketplace: large title, search, stories, quick actions, recommended ads, feed tabs and a tab bar.

      Pro

    Häufige Fragen

    Funktioniert next-pwa mit Next.js 16?

    Nicht ohne Weiteres. Das ursprüngliche Paket next-pwa ist ein Webpack-Plugin, dessen letzte Version 5.6.0 aus dem August 2022 stammt, und Next.js 16 baut mit Turbopack. next build bricht deshalb an der Webpack-Konfiguration ab, die das Plugin hinzufügt, solange du nicht --webpack übergibst. Nimm für eine Offline-Seite einen selbst geschriebenen Service Worker, oder Serwist, dessen Paket @serwist/turbopack (9.5.13, Oktober 2026) in der Doku ein Setup für Turbopack hat.

    Braucht eine Next.js PWA einen Service Worker, um installierbar zu sein?

    In aktuellen Chromium-Browsern und auf dem iPhone nicht: Ein Manifest mit name, Icons in 192px und 512px, start_url und standalone-Display, über HTTPS ausgeliefert, reicht für die Installation aus dem Browsermenü. Für eine Offline-Seite, Push-Benachrichtigungen und das automatische beforeinstallprompt-Event in Chrome willst du trotzdem einen.

    Warum erscheint meine Offline-Seite in Next.js ohne Styles?

    CSS und JavaScript der Seite liegen in gehashten Dateien unter /_next/static, die dein Worker nie gecacht hat. Offline lädt also das HTML, das Stylesheet aber nicht. Halte die Offline-Seite eigenständig, mit Inline-CSS in public/offline.html, so wie es das Offline-Fallback-Rezept von web.dev vorsieht.

    Wie teste ich einen Service Worker in Next.js lokal?

    Führ next build und next start aus und öffne http://localhost:3000 (opens in a new tab). localhost gilt als sicherer Kontext, der Worker registriert sich also ohne HTTPS. In den Chrome DevTools zeigt Application das Manifest und den Worker, und mit der Option Offline im Network-Panel lädst du die Seite neu und landest auf der Offline-Seite.

    Gibt es ein Next.js PWA Template mit App Shell?

    App Shell, Bottom Tab Bar, Install Prompt und der Block Mobile App Home von Wingo UI liefern die Schicht für die installierte App: Top Bar, Bottom Tabs mit Safe Areas, eine Drawer-Navigation auf dem Smartphone und ein Installationsbanner. Sie gehören zu Pro und werden mit npx wingo-ui@latest add als Quellcode installiert.

    In deinem Projekt ausprobieren

    Install Prompt

    Pro

    A React PWA install prompt: the browser's install dialog in Chrome and Edge, and an Add to Home Screen guide on iPhone and Mac.

    75 Komponenten kostenlos, ohne Konto. Pro ab 8 $ im Monat.

    Install Prompt live öffnenPreise ansehen
    • Mobile UI
    • PWA
    • Next.js
    • Service Worker
    • App Router

    Teilen

    SR

    Über den Autor

    Serban Rusu

    Gründer von Wingo UI

    Serban Rusu hat Wingo UI gegründet. Er baut die Komponenten, die CLI und den MCP-Server und schreibt über React-UIs für Smartphones und KI-Agents.

    Mehr von Serban
    Weiterlesen

    Ähnliche Artikel

    Alle Artikel
    Mobile UI mit React

    Shadcn Sidebar Mobile: Sheet reparieren, Tab Bar ergänzen

    Shadcn sidebar mobile reparieren: Sheet beim Navigieren schließen, versteckten Titel ergänzen, Höhen-Bugs beheben und am Handy eine Bottom Tab Bar dazunehmen.

    SRSerban Rusu·5. Nov. 2026·9 Min. Lesezeit
    Mobile UI mit React

    React Bottom Navigation Bar: Safe Areas und Badges

    React Bottom Navigation Bar in Next.js: 3 bis 5 Tabs, Safe Areas, Badges, die Screenreader vorlesen, Ausblenden beim Scrollen und wann die Sidebar besser passt.

    SRSerban Rusu·9. Okt. 2026·9 Min. Lesezeit
    Vergleiche und Alternativen

    React Native vs PWA 2026: Was brauchst du wirklich?

    React Native vs PWA 2026 im Check: Push, Offline, Installation, Gesten und Store. Welche iPhone-Grenzen entscheiden und wann eine React PWA reicht.

    SRSerban Rusu·16. Okt. 2026·12 Min. Lesezeit
    Newsletter

    Neue Artikel per E-Mail

    Neue Artikel, Produktneuheiten und gelegentlich Angebote von Wingo UI. Wir zählen Klicks, damit es relevant bleibt.

    Kein Spam. Du kannst dich jederzeit abmelden.

    WingoUI

    Animierte, konfigurierbare, mobile-first React-Komponenten und Blöcke. Kopier den Quellcode, pass ihn an und lass deinen Coding-Agenten damit bauen.

    Produkt

    • Komponenten
    • Vorlagen
    • Preise
    • KI-Agenten
    • Für Teams
    • Theme-Generator

    Ressourcen

    • Doku
    • Kontakt
    • Programme
    • Blog
    • Changelog
    • Changelog-RSS
    • llms.txt

    Vergleiche

    • Wingo UI vs. Premium-Kits
    • Wingo UI vs. shadcn/ui
    • shadcn/ui-Alternativen
    • MUI-Alternativen
    • Tailwind-Plus-Alternativen
    • Magic-UI-Alternativen
    • Kostenlose Komponenten

    Rechtliches

    • AGB
    • Datenschutz
    • Rückerstattung
    • Lizenz
    • Impressum

    Komponenten-Kategorien

    • Buttons & Actions
    • Inputs
    • Forms
    • Navigation
    • Overlays
    • Feedback
    • Data Display
    • Tables & Lists
    • Charts & Stats
    • Layout
    • Media
    • AI Kit
    • Text & Effects
    • Mobile
    • Commerce
    • Marketing Sections
    • Blocks
    • Hooks & Utilities

    © 2026 Wingo UI

    Wingo UI