Deutsch

Nutzen Sie die Power des Next.js App Routers mit unserem Guide für dateibasiertes Routing. Lernen Sie App-Struktur, dynamische Routen, Layouts und mehr.

Next.js App Router: Ein umfassender Leitfaden für dateibasiertes Routing

Der Next.js App Router, eingeführt in Next.js 13 und in späteren Versionen zum Standard geworden, revolutioniert die Art und Weise, wie wir Anwendungen strukturieren und in ihnen navigieren. Er führt ein leistungsstarkes und intuitives dateibasiertes Routing-System ein, das die Entwicklung vereinfacht, die Leistung verbessert und die allgemeine Entwicklererfahrung steigert. Dieser umfassende Leitfaden wird tief in das dateibasierte Routing des App Routers eintauchen und Ihnen das Wissen und die Fähigkeiten vermitteln, um robuste und skalierbare Next.js-Anwendungen zu erstellen.

Was ist dateibasiertes Routing?

Dateibasiertes Routing ist ein System, bei dem die Struktur der Routen Ihrer Anwendung direkt durch die Organisation Ihrer Dateien und Verzeichnisse bestimmt wird. Im Next.js App Router definieren Sie Routen, indem Sie Dateien im `app`-Verzeichnis erstellen. Jeder Ordner repräsentiert ein Routensegment, und spezielle Dateien in diesen Ordnern definieren, wie dieses Routensegment behandelt wird. Dieser Ansatz bietet mehrere Vorteile:

Erste Schritte mit dem App Router

Um den App Router zu verwenden, müssen Sie ein neues Next.js-Projekt erstellen oder ein bestehendes Projekt migrieren. Stellen Sie sicher, dass Sie Next.js Version 13 oder neuer verwenden.

Ein neues Projekt erstellen:

Sie können ein neues Next.js-Projekt mit dem App Router mit dem folgenden Befehl erstellen:

npx create-next-app@latest my-app --example with-app

Migration eines bestehenden Projekts:

Um ein bestehendes Projekt zu migrieren, müssen Sie Ihre Seiten aus dem `pages`-Verzeichnis in das `app`-Verzeichnis verschieben. Möglicherweise müssen Sie Ihre Routing-Logik entsprechend anpassen. Next.js bietet einen Migrationsleitfaden, der Sie bei diesem Prozess unterstützt.

Kernkonzepte des dateibasierten Routings

Der App Router führt mehrere spezielle Dateien und Konventionen ein, die definieren, wie Ihre Routen behandelt werden:

1. Das `app`-Verzeichnis

Das `app`-Verzeichnis ist die Wurzel der Routen Ihrer Anwendung. Alle Dateien und Ordner in diesem Verzeichnis werden zur Generierung von Routen verwendet. Alles außerhalb des `app`-Verzeichnisses (wie das `pages`-Verzeichnis, falls Sie migrieren) wird vom App Router ignoriert.

2. Die `page.js`-Datei

Die `page.js` (oder `page.jsx`, `page.ts`, `page.tsx`)-Datei ist der fundamentalste Teil des App Routers. Sie definiert die UI-Komponente, die für ein bestimmtes Routensegment gerendert wird. Es ist eine **erforderliche** Datei für jedes Routensegment, auf das direkt zugegriffen werden soll.

Beispiel:

Wenn Sie eine Dateistruktur wie diese haben:

app/
  about/
    page.js

Die aus `app/about/page.js` exportierte Komponente wird gerendert, wenn ein Benutzer zu `/about` navigiert.

// app/about/page.js
import React from 'react';

export default function AboutPage() {
  return (
    <div>
      <h1>Über uns</h1>
      <p>Erfahren Sie mehr über unser Unternehmen.</p>
    </div>
  );
}

3. Die `layout.js`-Datei

Die `layout.js` (oder `layout.jsx`, `layout.ts`, `layout.tsx`)-Datei definiert eine Benutzeroberfläche, die über mehrere Seiten innerhalb eines Routensegments hinweg geteilt wird. Layouts sind nützlich, um konsistente Kopfzeilen, Fußzeilen, Seitenleisten und andere Elemente zu erstellen, die auf mehreren Seiten vorhanden sein sollen.

Beispiel:

Nehmen wir an, Sie möchten sowohl der `/about`-Seite als auch einer hypothetischen `/about/team`-Seite eine Kopfzeile hinzufügen. Sie können eine `layout.js`-Datei im `app/about`-Verzeichnis erstellen:

// app/about/layout.js
import React from 'react';

export default function AboutLayout({ children }) {
  return (
    <div>
      <header>
        <h1>Über unser Unternehmen</h1>
      </header>
      <main>{children}</main>
    </div>
  );
}

Die `children`-Prop wird durch die UI ersetzt, die von der `page.js`-Datei im selben Verzeichnis oder in verschachtelten Verzeichnissen gerendert wird.

4. Die `template.js`-Datei

Die `template.js`-Datei ist ähnlich wie `layout.js`, aber sie erstellt eine neue Instanz der Komponente für jede untergeordnete Route. Dies ist nützlich für Szenarien, in denen Sie den Komponentenzustand beibehalten oder Neu-Renderings beim Navigieren zwischen untergeordneten Routen verhindern möchten. Im Gegensatz zu Layouts werden Templates bei der Navigation neu gerendert. Templates eignen sich hervorragend, um Elemente bei der Navigation zu animieren.

Beispiel:

// app/template.js
'use client'

import { useState } from 'react'

export default function Template({ children }) {
  const [count, setCount] = useState(0)

  return (
    <main>
      <p>Template: {count}</p>
      <button onClick={() => setCount(count + 1)}>Template aktualisieren</button>
      {children}
    </main>
  )
}

5. Die `loading.js`-Datei

Die `loading.js` (oder `loading.jsx`, `loading.ts`, `loading.tsx`)-Datei ermöglicht es Ihnen, eine Lade-UI zu erstellen, die angezeigt wird, während ein Routensegment geladen wird. Dies ist nützlich, um eine bessere Benutzererfahrung beim Abrufen von Daten oder bei der Durchführung anderer asynchroner Operationen zu bieten.

Beispiel:

// app/about/loading.js
import React from 'react';

export default function Loading() {
  return <p>Lade Informationen zu Über uns...</p>;
}

Wenn ein Benutzer zu `/about` navigiert, wird die `Loading`-Komponente angezeigt, bis die `page.js`-Komponente vollständig gerendert ist.

6. Die `error.js`-Datei

Die `error.js` (oder `error.jsx`, `error.ts`, `error.tsx`)-Datei ermöglicht es Ihnen, eine benutzerdefinierte Fehler-UI zu erstellen, die angezeigt wird, wenn ein Fehler innerhalb eines Routensegments auftritt. Dies ist nützlich, um eine benutzerfreundlichere Fehlermeldung bereitzustellen und zu verhindern, dass die gesamte Anwendung abstürzt.

Beispiel:

// app/about/error.js
'use client'

import React from 'react';

export default function Error({ error, reset }) {
  return (
    <div>
      <h2>Ein Fehler ist aufgetreten!</h2>
      <p>{error.message}</p>
      <button onClick={() => reset()}>Erneut versuchen</button>
    </div>
  );
}

Wenn beim Rendern der `/about`-Seite ein Fehler auftritt, wird die `Error`-Komponente angezeigt. Die `error`-Prop enthält Informationen über den Fehler, und die `reset`-Funktion ermöglicht es dem Benutzer, zu versuchen, die Seite neu zu laden.

7. Routengruppen (Route Groups)

Routengruppen `(groupName)` ermöglichen es Ihnen, Ihre Routen zu organisieren, ohne die URL-Struktur zu beeinflussen. Sie werden erstellt, indem ein Ordnername in Klammern gesetzt wird. Dies ist besonders hilfreich für die Organisation von Layouts und gemeinsam genutzten Komponenten.

Beispiel:

app/
  (marketing)/
    about/
      page.js
    contact/
      page.js
  (shop)/
    products/
      page.js

In diesem Beispiel sind die Seiten `about` und `contact` unter der `marketing`-Gruppe zusammengefasst, und die `products`-Seite befindet sich in der `shop`-Gruppe. Die URLs bleiben `/about`, `/contact` bzw. `/products`.

8. Dynamische Routen

Dynamische Routen ermöglichen es Ihnen, Routen mit variablen Segmenten zu erstellen. Dies ist nützlich, um Inhalte basierend auf Daten anzuzeigen, die aus einer Datenbank oder API abgerufen werden. Dynamische Routensegmente werden definiert, indem der Segmentname in eckige Klammern gesetzt wird (z. B. `[id]`)

Beispiel:

Nehmen wir an, Sie möchten eine Route zur Anzeige einzelner Blog-Beiträge basierend auf ihrer ID erstellen. Sie können eine Dateistruktur wie diese erstellen:

app/
  blog/
    [id]/
      page.js

Das `[id]`-Segment ist ein dynamisches Segment. Die aus `app/blog/[id]/page.js` exportierte Komponente wird gerendert, wenn ein Benutzer zu einer URL wie `/blog/123` oder `/blog/456` navigiert. Der Wert des `id`-Parameters ist in der `params`-Prop der Komponente verfügbar.

// app/blog/[id]/page.js
import React from 'react';

export default async function BlogPost({ params }) {
  const { id } = params;

  // Daten für den Blog-Beitrag mit der angegebenen ID abrufen
  const post = await fetchBlogPost(id);

  if (!post) {
    return <p>Blog-Beitrag nicht gefunden.</p>;
  }

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  );
}

async function fetchBlogPost(id) {
  // Simuliert das Abrufen von Daten aus einer Datenbank oder API
  return new Promise((resolve) => {
    setTimeout(() => {
      const posts = {
        '123': { title: 'Mein erster Blog-Beitrag', content: 'Dies ist der Inhalt meines ersten Blog-Beitrags.' },
        '456': { title: 'Ein weiterer Blog-Beitrag', content: 'Hier ist noch mehr spannender Inhalt.' },
      };
      resolve(posts[id] || null);
    }, 500);
  });
}

Sie können auch mehrere dynamische Segmente in einer Route verwenden. Zum Beispiel könnten Sie eine Route wie `/blog/[category]/[id]` haben.

9. Catch-all-Segmente

Catch-all-Segmente ermöglichen es Ihnen, Routen zu erstellen, die auf eine beliebige Anzahl von Segmenten passen. Dies ist nützlich für Szenarien wie die Erstellung eines CMS, bei dem die URL-Struktur vom Benutzer bestimmt wird. Catch-all-Segmente werden definiert, indem drei Punkte vor dem Segmentnamen hinzugefügt werden (z. B. `[...slug]`)

Beispiel:

app/
  docs/
    [...slug]/
      page.js

Das `[...slug]`-Segment passt auf eine beliebige Anzahl von Segmenten nach `/docs`. Zum Beispiel passt es auf `/docs/getting-started`, `/docs/api/users` und `/docs/advanced/configuration`. Der Wert des `slug`-Parameters ist ein Array, das die übereinstimmenden Segmente enthält.

// app/docs/[...slug]/page.js
import React from 'react';

export default function DocsPage({ params }) {
  const { slug } = params;

  return (
    <div>
      <h1>Docs</h1>
      <p>Slug: {slug ? slug.join('/') : 'Kein Slug'}</p>
    </div>
  );
}

Optionale Catch-all-Segmente können erstellt werden, indem der Segmentname in doppelte eckige Klammern gesetzt wird `[[...slug]]`. Dadurch wird das Routensegment optional. Beispiel:

app/
  blog/
    [[...slug]]/
      page.js

Dieses Setup rendert die page.js-Komponente sowohl unter `/blog` als auch unter `/blog/any/number/of/segments`.

10. Parallele Routen

Parallele Routen ermöglichen es Ihnen, eine oder mehrere Seiten gleichzeitig im selben Layout zu rendern. Dies ist besonders nützlich für komplexe Layouts wie Dashboards, bei denen verschiedene Abschnitte der Seite unabhängig voneinander geladen werden können. Parallele Routen werden mit dem `@`-Symbol gefolgt von einem Slot-Namen definiert (z. B. `@sidebar`, `@main`).

Beispiel:

app/
  @sidebar/
    page.js  // Inhalt für die Seitenleiste
  @main/
    page.js  // Inhalt für den Hauptbereich
  default.js // Erforderlich: Definiert das Standardlayout für parallele Routen

Die `default.js`-Datei ist erforderlich, wenn parallele Routen verwendet werden. Sie definiert, wie die verschiedenen Slots kombiniert werden, um das endgültige Layout zu erstellen.

// app/default.js
export default function RootLayout({ children: { sidebar, main } }) {
  return (
    <div style={{ display: 'flex' }}>
      <aside style={{ width: '200px', backgroundColor: '#f0f0f0' }}>
        {sidebar}
      </aside>
      <main style={{ flex: 1, padding: '20px' }}>
        {main}
      </main>
    </div>
  );
}

11. Abfangende Routen (Intercepting Routes)

Abfangende Routen ermöglichen es Ihnen, eine Route aus einem anderen Teil Ihrer Anwendung innerhalb des aktuellen Layouts zu laden. Dies ist nützlich für die Erstellung von Modals, Bildergalerien und anderen UI-Elementen, die über dem bestehenden Seiteninhalt erscheinen sollen. Abfangende Routen werden mit der `(..)`-Syntax definiert, die angibt, wie viele Ebenen im Verzeichnisbaum nach oben gegangen werden muss, um die abgefangene Route zu finden.

Beispiel:

app/
  (.)photos/
    [id]/
      page.js  // Die abgefangene Route
  feed/
    page.js  // Die Seite, auf der das Foto-Modal angezeigt wird

In diesem Beispiel wird, wenn ein Benutzer auf der `/feed`-Seite auf ein Foto klickt, die `app/(.)photos/[id]/page.js`-Route abgefangen und als Modal über der `/feed`-Seite angezeigt. Die `(.)`-Syntax weist Next.js an, eine Ebene höher (zum `app`-Verzeichnis) zu suchen, um die `photos/[id]`-Route zu finden.

Datenabruf mit dem App Router

Der App Router bietet integrierte Unterstützung für den Datenabruf mit Server Components und Client Components. Server Components werden auf dem Server gerendert, während Client Components auf dem Client gerendert werden. Dies ermöglicht es Ihnen, für jede Komponente den besten Ansatz basierend auf ihren Anforderungen zu wählen.

Server Components

Server Components sind der Standard im App Router. Sie ermöglichen es Ihnen, Daten direkt in Ihren Komponenten abzurufen, ohne dass separate API-Routen erforderlich sind. Dies kann die Leistung verbessern und Ihren Code vereinfachen.

Beispiel:

// app/products/page.js
import React from 'react';

export default async function ProductsPage() {
  const products = await fetchProducts();

  return (
    <div>
      <h1>Produkte</h1>
      <ul>
        {products.map((product) => (
          <li key={product.id}>{product.name}</li>
        ))}
      </ul>
    </div>
  );
}

async function fetchProducts() {
  // Simuliert das Abrufen von Daten aus einer Datenbank oder API
  return new Promise((resolve) => {
    setTimeout(() => {
      const products = [
        { id: 1, name: 'Produkt A' },
        { id: 2, name: 'Produkt B' },
        { id: 3, name: 'Produkt C' },
      ];
      resolve(products);
    }, 500);
  });
}

In diesem Beispiel wird die `fetchProducts`-Funktion direkt in der `ProductsPage`-Komponente aufgerufen. Die Komponente wird auf dem Server gerendert, und die Daten werden abgerufen, bevor der HTML-Code an den Client gesendet wird.

Client Components

Client Components werden auf dem Client gerendert und ermöglichen die Verwendung von clientseitigen Funktionen wie Event-Listenern, Zustand und Browser-APIs. Um eine Client Component zu verwenden, müssen Sie die Direktive `'use client'` am Anfang der Datei hinzufügen.

Beispiel:

// app/counter/page.js
'use client'

import React, { useState } from 'react';

export default function CounterPage() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <h1>Zähler</h1>
      <p>Stand: {count}</p>
      <button onClick={() => setCount(count + 1)}>Erhöhen</button>
    </div>
  );
}

In diesem Beispiel ist die `CounterPage`-Komponente eine Client Component, da sie den `useState`-Hook verwendet. Die `'use client'`-Direktive weist Next.js an, diese Komponente auf dem Client zu rendern.

Fortgeschrittene Routing-Techniken

Der App Router bietet mehrere fortgeschrittene Routing-Techniken, die zur Erstellung komplexer und anspruchsvoller Anwendungen verwendet werden können.

1. Route Handlers

Route Handlers ermöglichen es Ihnen, API-Endpunkte innerhalb Ihres `app`-Verzeichnisses zu erstellen. Dies eliminiert die Notwendigkeit eines separaten `pages/api`-Verzeichnisses. Route Handlers werden in Dateien namens `route.js` (oder `route.ts`) definiert und exportieren Funktionen, die verschiedene HTTP-Methoden behandeln (z.B. `GET`, `POST`, `PUT`, `DELETE`).

Beispiel:

// app/api/users/route.js
import { NextResponse } from 'next/server'

export async function GET(request) {
  // Simuliert das Abrufen von Benutzern aus einer Datenbank
  const users = [
    { id: 1, name: 'John Doe' },
    { id: 2, name: 'Jane Doe' },
  ];

  return NextResponse.json(users);
}

export async function POST(request) {
  const body = await request.json()
  console.log('Empfangene Daten:', body)
  return NextResponse.json({ message: 'Benutzer erstellt' }, { status: 201 })
}

Dieses Beispiel definiert einen Route Handler unter `/api/users`, der sowohl `GET`- als auch `POST`-Anfragen behandelt. Die `GET`-Funktion gibt eine Liste von Benutzern zurück, und die `POST`-Funktion erstellt einen neuen Benutzer.

2. Routengruppen mit mehreren Layouts

Sie können Routengruppen mit Layouts kombinieren, um unterschiedliche Layouts für verschiedene Bereiche Ihrer Anwendung zu erstellen. Dies ist nützlich für Szenarien, in denen Sie eine andere Kopfzeile oder Seitenleiste für verschiedene Teile Ihrer Website haben möchten.

Beispiel:

app/
  (marketing)/
    layout.js  // Marketing-Layout
    about/
      page.js
    contact/
      page.js
  (admin)/
    layout.js  // Admin-Layout
    dashboard/
      page.js

In diesem Beispiel verwenden die Seiten `about` und `contact` das `marketing`-Layout, während die `dashboard`-Seite das `admin`-Layout verwendet.

3. Middleware

Middleware ermöglicht es Ihnen, Code auszuführen, bevor eine Anfrage von Ihrer Anwendung bearbeitet wird. Dies ist nützlich für Aufgaben wie Authentifizierung, Autorisierung, Protokollierung und die Umleitung von Benutzern basierend auf ihrem Standort oder Gerät.

Middleware wird in einer Datei namens `middleware.js` (oder `middleware.ts`) im Stammverzeichnis Ihres Projekts definiert.

Beispiel:

// middleware.js
import { NextResponse } from 'next/server'

export function middleware(request) {
  // Prüfen, ob der Benutzer authentifiziert ist
  const isAuthenticated = false; // Ersetzen Sie dies durch Ihre Authentifizierungslogik

  if (!isAuthenticated && request.nextUrl.pathname.startsWith('/admin')) {
    return NextResponse.redirect(new URL('/login', request.url));
  }

  return NextResponse.next();
}

// Siehe "Matching Paths" unten, um mehr zu erfahren
export const config = {
  matcher: '/admin/:path*',
}

Dieses Beispiel definiert eine Middleware, die prüft, ob der Benutzer authentifiziert ist, bevor ihm der Zugriff auf eine Route unter `/admin` erlaubt wird. Wenn der Benutzer nicht authentifiziert ist, wird er auf die `/login`-Seite umgeleitet.

Best Practices für dateibasiertes Routing

Um das dateibasierte Routing-System des App Routers optimal zu nutzen, beachten Sie die folgenden Best Practices:

Beispiele für Internationalisierung mit dem Next.js App Router

Der Next.js App Router vereinfacht die Internationalisierung (i18n) durch dateibasiertes Routing. So können Sie i18n effektiv implementieren:

1. Sub-Pfad-Routing

Organisieren Sie Ihre Routen basierend auf der Locale über Sub-Pfade. Zum Beispiel:

app/
  [locale]/
    page.tsx         // Startseite für das Locale
    about/
      page.tsx     // Über-uns-Seite für das Locale
// app/[locale]/page.tsx
import { getTranslations } from './dictionaries';

export default async function HomePage({ params: { locale } }) {
  const t = await getTranslations(locale);
  return (<h1>{t.home.title}</h1>);
}

// dictionaries.js
const dictionaries = {
  en: () => import('./dictionaries/en.json').then((module) => module.default),
  es: () => import('./dictionaries/es.json').then((module) => module.default),
};

export const getTranslations = async (locale) => {
  try {
    return dictionaries[locale]() ?? dictionaries.en();
  } catch (error) {
    console.error(`Fehler beim Laden der Übersetzungen für Locale ${locale}`, error);
    return dictionaries.en();
  }
};

In diesem Setup behandelt das dynamische Routensegment `[locale]` verschiedene Locales (z. B. `/en`, `/es`). Die Übersetzungen werden dynamisch basierend auf der Locale geladen.

2. Domain-Routing

Für einen fortgeschritteneren Ansatz können Sie für jede Locale unterschiedliche Domains oder Subdomains verwenden. Dies erfordert oft zusätzliche Konfiguration bei Ihrem Hosting-Anbieter.

3. Middleware zur Locale-Erkennung

Verwenden Sie Middleware, um die bevorzugte Locale des Benutzers automatisch zu erkennen und ihn entsprechend weiterzuleiten.

// middleware.js
import { NextResponse } from 'next/server';
import { match } from '@formatjs/intl-localematcher';
import Negotiator from 'negotiator';

let locales = ['en', 'es', 'fr'];

function getLocale(request) {
  const negotiatorHeaders = {};
  request.headers.forEach((value, key) => (negotiatorHeaders[key] = value));
  let languages = new Negotiator({ headers: negotiatorHeaders }).languages();

  try {
      return match(languages, locales, 'en'); // "en" als Standard-Locale verwenden
  } catch (error) {
      console.error("Fehler beim Abgleich der Locale:", error);
      return 'en'; // Fallback auf Englisch, wenn der Abgleich fehlschlägt
  }
}

export function middleware(request) {
  const pathname = request.nextUrl.pathname;
  const pathnameIsMissingLocale = locales.every(
    (locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`
  );

  if (pathnameIsMissingLocale) {
    const locale = getLocale(request);

    return NextResponse.redirect(
      new URL(
        `/${locale}${pathname.startsWith('/') ? '' : '/'}${pathname}`,
        request.url
      )
    );
  }
}

export const config = {
  matcher: [
    '/((?!api|_next/static|_next/image|favicon.ico).*)',
  ],
};

Diese Middleware prüft, ob der angeforderte Pfad ein Locale-Präfix hat. Wenn nicht, erkennt sie die bevorzugte Locale des Benutzers mithilfe des `Accept-Language`-Headers und leitet ihn zum entsprechenden Locale-spezifischen Pfad weiter. Bibliotheken wie `@formatjs/intl-localematcher` und `negotiator` werden verwendet, um die Locale-Verhandlung zu handhaben.

Next.js App Router und globale Barrierefreiheit

Die Erstellung global zugänglicher Webanwendungen erfordert eine sorgfältige Berücksichtigung der Prinzipien der Barrierefreiheit (a11y). Der Next.js App Router bietet eine solide Grundlage für den Aufbau barrierefreier Erfahrungen, aber es ist unerlässlich, Best Practices zu implementieren, um sicherzustellen, dass Ihre Anwendung von jedem, unabhängig von seinen Fähigkeiten, nutzbar ist.

Wichtige Überlegungen zur Barrierefreiheit

  1. Semantisches HTML: Verwenden Sie semantische HTML-Elemente (z. B. `<article>`, `<nav>`, `<aside>`, `<main>`), um Ihren Inhalt zu strukturieren. Dies gibt assistiven Technologien eine Bedeutung und hilft Benutzern, Ihre Website leichter zu navigieren.
  2. ARIA-Attribute: Verwenden Sie ARIA (Accessible Rich Internet Applications)-Attribute, um die Barrierefreiheit von benutzerdefinierten Komponenten und Widgets zu verbessern. ARIA-Attribute liefern assistiven Technologien zusätzliche Informationen über die Rolle, den Zustand und die Eigenschaften von Elementen.
  3. Tastaturnavigation: Stellen Sie sicher, dass alle interaktiven Elemente über die Tastatur zugänglich sind. Benutzer sollten in der Lage sein, mit der `Tab`-Taste durch Ihre Anwendung zu navigieren und mit Elementen über die `Enter`- oder `Leertaste` zu interagieren.
  4. Farbkontrast: Verwenden Sie einen ausreichenden Farbkontrast zwischen Text und Hintergrund, um die Lesbarkeit für Benutzer mit Sehbehinderungen zu gewährleisten. Die Web Content Accessibility Guidelines (WCAG) empfehlen ein Kontrastverhältnis von mindestens 4.5:1 für normalen Text und 3:1 für großen Text.
  5. Bild-Alternativtext: Geben Sie beschreibenden Alternativtext für alle Bilder an. Alternativtext bietet eine Textalternative für Bilder, die von Screenreadern gelesen werden kann.
  6. Formularbeschriftungen: Verknüpfen Sie Formularbeschriftungen mit ihren entsprechenden Eingabefeldern unter Verwendung des `<label>`-Elements. Dies macht den Benutzern deutlich, welche Informationen in jedem Feld erwartet werden.
  7. Testen mit Screenreadern: Testen Sie Ihre Anwendung mit einem Screenreader, um sicherzustellen, dass sie für Benutzer mit Sehbehinderungen zugänglich ist. Beliebte Screenreader sind NVDA, JAWS und VoiceOver.

Implementierung von Barrierefreiheit im Next.js App Router

  1. Verwenden Sie die Next.js Link-Komponente: Verwenden Sie die `<Link>`-Komponente für die Navigation. Sie bietet integrierte Barrierefreiheitsfunktionen wie Prefetching und Fokusmanagement.
  2. Fokusmanagement: Stellen Sie beim Navigieren zwischen Seiten oder beim Öffnen von Modals sicher, dass der Fokus ordnungsgemäß verwaltet wird. Der Fokus sollte auf das logischste Element auf der neuen Seite oder im Modal gesetzt werden.
  3. Barrierefreie benutzerdefinierte Komponenten: Stellen Sie beim Erstellen benutzerdefinierter Komponenten sicher, dass diese barrierefrei sind, indem Sie die oben genannten Prinzipien befolgen. Verwenden Sie semantisches HTML, ARIA-Attribute und Tastaturnavigation, um Ihre Komponenten für alle nutzbar zu machen.
  4. Linting und Testing: Verwenden Sie Linting-Tools wie ESLint mit Barrierefreiheits-Plugins, um potenzielle Barrierefreiheitsprobleme in Ihrem Code zu identifizieren. Verwenden Sie außerdem automatisierte Testwerkzeuge, um Ihre Anwendung auf Verstöße gegen die Barrierefreiheit zu testen.

Fazit

Das dateibasierte Routing-System des Next.js App Routers bietet eine leistungsstarke und intuitive Möglichkeit, Ihre Anwendungen zu strukturieren und zu navigieren. Indem Sie die in diesem Leitfaden beschriebenen Kernkonzepte und Best Practices verstehen, können Sie robuste, skalierbare und wartbare Next.js-Anwendungen erstellen. Experimentieren Sie mit den verschiedenen Funktionen des App Routers und entdecken Sie, wie er Ihren Entwicklungsworkflow vereinfachen und die Benutzererfahrung verbessern kann.