Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
YouTube Security VideosGoogle Chrome: Unfinished Projects: Solange’s Public Sculpture(21.09.2026 um 17:02 Uhr)
Windows Tipps & SecurityBlurry or pixelated video in Microsoft Teams(21.09.2026 um 14:34 Uhr)
Sicherheitslücken (CVE)USN-8791-1: Ghostscript vulnerability(21.09.2026 um 14:51 Uhr)
Sicherheitslücken (CVE)USN-8792-1: Memcached vulnerability(21.09.2026 um 15:02 Uhr)
Sichere ProgrammierungI stopped rewriting the same Electron boilerplate — so I packaged it(21.09.2026 um 17:28 Uhr)
YouTube Security VideosGoogle Chrome: Unfinished Projects: Solange’s Public Sculpture(21.09.2026 um 17:02 Uhr)
Windows Tipps & SecurityBlurry or pixelated video in Microsoft Teams(21.09.2026 um 14:34 Uhr)
Sicherheitslücken (CVE)USN-8791-1: Ghostscript vulnerability(21.09.2026 um 14:51 Uhr)
Sicherheitslücken (CVE)USN-8792-1: Memcached vulnerability(21.09.2026 um 15:02 Uhr)
Sichere ProgrammierungI stopped rewriting the same Electron boilerplate — so I packaged it(21.09.2026 um 17:28 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

Storybook 8 with Next.js: Complete Guide (2026)

The gap between writing a component and being confident it works across all its states — loading, empty, error, mobile, dark mode — is where most UI bugs live. Storybook 8 closes that gap by letting you develop and test components in com…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

The gap between writing a component and being confident it works across all its states — loading, empty, error, mobile, dark mode — is where most UI bugs live. Storybook 8 closes that gap by letting you develop and test components in complete isolation, with first-class support for Next.js App Router and React Server Components.






Installation






npx storybook@latest init






The init command detects Next.js automatically and installs @storybook/nextjs — which handles next/image, next/link, next/navigation hooks, and static file serving automatically.




npm run storybook









Story Format: CSF3






// components/ui/Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react'
import { Button } from './Button'

const meta: Meta<typeof Button> = {
title: 'UI/Button',
component: Button,
tags: ['autodocs'], // generates documentation page automatically
args: {
children: 'Click me',
},
argTypes: {
variant: {
control: 'select',
options: ['default', 'destructive', 'outline', 'ghost'],
},
size: {
control: 'radio',
options: ['sm', 'default', 'lg'],
},
},
}

export default meta
type Story = StoryObj<typeof Button>

export const Default: Story = {}

export const Destructive: Story = {
args: { variant: 'destructive', children: 'Delete account' },
}

export const Loading: Story = {
args: { disabled: true, children: 'Saving...' },
}









Decorators: Providers for Every Story






// .storybook/preview.ts
import type { Preview } from '@storybook/react'
import { ThemeProvider } from '../src/components/theme-provider'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import '../src/app/globals.css'

const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } })

const preview: Preview = {
decorators: [
(Story) => (
<QueryClientProvider client={queryClient}>
<ThemeProvider defaultTheme="dark">
<Story />
</ThemeProvider>
</QueryClientProvider>
),
],
parameters: {
backgrounds: {
default: 'dark',
values: [
{ name: 'dark', value: '#0D1117' },
{ name: 'light', value: '#ffffff' },
],
},
layout: 'centered',
},
}

export default preview









The play Function: Interaction Testing



The play function runs after a story renders, simulates interactions, and asserts on results:




// components/forms/LoginForm.stories.tsx
import { expect, userEvent, within, fn } from '@storybook/test'
import { LoginForm } from './LoginForm'

const meta: Meta<typeof LoginForm> = {
component: LoginForm,
args: { onSubmit: fn() },
}
export default meta
type Story = StoryObj<typeof LoginForm>

export const ValidSubmission: Story = {
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement)

await userEvent.type(canvas.getByLabelText('Email'), '[email protected]')
await userEvent.type(canvas.getByLabelText('Password'), 'correcthorse')
await userEvent.click(canvas.getByRole('button', { name: /sign in/i }))

await expect(args.onSubmit).toHaveBeenCalledWith({
email: '[email protected]',
password: 'correcthorse',
})
},
}

export const ValidationErrors: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement)
await userEvent.click(canvas.getByRole('button', { name: /sign in/i }))
await expect(canvas.getByText('Email is required')).toBeInTheDocument()
await expect(canvas.getByText('Password is required')).toBeInTheDocument()
},
}









Running Interaction Tests in CI






npm install --save-dev @storybook/test-runner









# .github/workflows/storybook.yml
- name: Build Storybook
run: npm run build-storybook

- name: Run interaction tests
run: |
npx concurrently -k -s first \
"npx http-server storybook-static --port 6006 --silent" \
"npx wait-on tcp:6006 && npm run test-storybook"









Mocking Next.js Navigation






const meta: Meta<typeof Breadcrumb> = {
component: Breadcrumb,
parameters: {
nextjs: {
appDirectory: true,
navigation: {
pathname: '/dashboard/users',
},
},
},
}

// Per-story override:
export const NestedPage: Story = {
parameters: {
nextjs: {
navigation: { pathname: '/dashboard/users/123/edit' },
},
},
}






useRouter, useParams, useSearchParams — all available through parameters.nextjs.navigation.






Mocking Server Actions






import { fn } from '@storybook/test'
import { TodoItem } from './TodoItem'

export default {
component: TodoItem,
args: {
onToggle: fn(),
onDelete: fn(),
},
}

export const DeleteFlow: Story = {
args: {
todo: { id: '1', title: 'Old task', completed: false },
},
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement)
await userEvent.click(canvas.getByRole('button', { name: /delete/i }))
await expect(args.onDelete).toHaveBeenCalledWith('1')
},
}









React Server Component Stories






// UserProfile.stories.tsx (RSC with mocked DB)
vi.mock('@/lib/db', () => ({
db: {
query: {
users: { findFirst: vi.fn() },
},
},
}))

export const WithUser: Story = {
args: { userId: 'user_123' },
beforeEach() {
const { db } = require('@/lib/db')
db.query.users.findFirst.mockResolvedValue({
id: 'user_123',
name: 'Alice Chen',
email: '[email protected]',
})
},
}

export const UserNotFound: Story = {
args: { userId: 'unknown' },
beforeEach() {
const { db } = require('@/lib/db')
db.query.users.findFirst.mockResolvedValue(null)
},
}









Viewport Testing






export const Mobile: Story = {
parameters: { viewport: { defaultViewport: 'mobile1' } },
}

export const Tablet: Story = {
parameters: { viewport: { defaultViewport: 'tablet' } },
}









Accessibility Testing






npm install --save-dev @storybook/addon-a11y









// .storybook/main.ts
addons: ['@storybook/addon-essentials', '@storybook/addon-a11y'],






Every story now has an Accessibility tab with axe violations. Assert on it in play:




import { checkA11y } from '@storybook/addon-a11y'

export const Accessible: Story = {
play: async ({ canvasElement }) => {
// ...interactions
await checkA11y(canvasElement)
},
}









Story Organization at Scale






src/components/
ui/
Button.stories.tsx → title: 'UI/Button'
Input.stories.tsx → title: 'UI/Input'
features/
users/
UserCard.stories.tsx → title: 'Features/Users/UserCard'
billing/
PlanCard.stories.tsx → title: 'Features/Billing/PlanCard'






tags: ['autodocs'] generates a documentation page with all stories, controls, and prop types automatically — no maintenance required.






Quick Reference






// Story structure
const meta: Meta<typeof Component> = {
component: Component,
tags: ['autodocs'],
args: { /* shared defaults */ },
argTypes: { variant: { control: 'select', options: [...] } },
decorators: [(Story) => <Provider><Story /></Provider>],
}
export default meta
type Story = StoryObj<typeof Component>
export const MyStory: Story = { args: { ... } }

// play function imports
import { expect, userEvent, within, fn } from '@storybook/test'

// play function
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement)
await userEvent.type(canvas.getByLabelText('Email'), '[email protected]')
await userEvent.click(canvas.getByRole('button', { name: /submit/i }))
await expect(args.onSubmit).toHaveBeenCalled()
}

// Next.js mock
parameters: { nextjs: { navigation: { pathname: '/dashboard' } } }

// Run CI tests
npx test-storybook






The workflow: for every component, write stories for the empty state, loading state, error state, and main success state before writing the component itself. It forces you to think through edge cases upfront, and you get visual regression tests as a side effect.






Full article at stacknotice.com/blog/storybook-nextjs-guide-2026

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Storybook 8 with Next.js: Complete Guide (2026)

Thematisch verwandte Begriffe: Storybook, with, Nextjs, Complete · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-94393 | When a user creates or edits a report inside an event, MISP can identify…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick