Alle skills
Developmentv1.0.0nextjs-conventions

Next.js-conventies

App Router en Tailwind v4

De App Router en Tailwind v4 straffen allebei gewoontes uit hun vorige versie af, en allebei doen ze dat zonder foutmelding. De pagina rendert, de klasse wordt genegeerd, er gebeurt niets zichtbaars. Deze skill is de verzameling regels die dat afvangt, met voor elke regel de reden waarom hij bestaat.

MITCCaiCxAgCuOc
Next.jsReactTailwindApp Router
Installeren

Zet hem in je eigen agent

Kies je client. Het commando staat er klaar voor.

claude code
/plugin marketplace add ASNNetworks/floh-skills
/plugin install nextjs-conventions@floh-skills

Typ deze twee in een Claude Code-sessie. De skill is meteen daarna beschikbaar; herstarten is niet nodig.

Wat je nodig hebt

  • Next.js 14 of hoger met de App Router
  • Tailwind CSS v4 voor het tweede deel
Demo

Zo ziet het eruit

Een echte sessie, stap voor stap afgespeeld.

claude-code
Wat het doet

De kern

De client-grens blijft klein

use client is geen oplossing voor een buildfout. Elke keer dat je hem toevoegt verhuist de component en zijn hele importboom naar de browserbundel.

De Tailwind v4-val

scale, translate en rotate zijn losse eigenschappen geworden. transition-transform animeert ze niet meer, dus je hover klapt in plaats van dat hij loopt. Niets faalt, het voelt alleen slordig.

Data op de server

Nooit je eigen API-route aanroepen vanuit een server component, dat is een HTTP-rondje naar jezelf. En nooit een skeleton tonen voor data die de server al had.

Klassen die echt bestaan

Tailwind leest je broncode als tekst. Een geïnterpoleerde klassenaam genereert niets, dus schrijf volledige strings en kies daartussen.

Wanneer

Wanneer je hem pakt

Een nieuwe pagina bouwen

Server component met await op params, generateMetadata, generateStaticParams, en de client-grens op het kleinste blaadje.

Migreren naar Tailwind v4

De vier stille breukvlakken op een rij: config in CSS, opacity via color-mix, losse transforms en de gewijzigde standaard-randkleur.

Een pull request reviewen

De checklist onderaan de skill loopt precies de dingen af die in review het vaakst blijven liggen.

Uitzoeken waarom een hover niet animeert

Bijna altijd transition-transform naast een v4-transform. Eén regel, en je zoekt er een half uur naar.

De inhoud

Lees hem voordat je hem draait

Dit is precies wat er in de map komt te staan. Geen verrassingen, geen verborgen stappen.

1 bestanden

SKILL.md
---
name: nextjs-conventions
description: Apply App Router and Tailwind v4 conventions correctly in a Next.js project — server vs client components, data fetching, metadata, and the Tailwind v4 changes that silently break v3 habits. Use when writing or reviewing Next.js pages, components, layouts, route handlers or Tailwind classes.
---

# Next.js App Router and Tailwind v4

The App Router and Tailwind v4 both punish habits carried over from their previous
versions, and both do it quietly: the page renders, the class is ignored, nothing errors.
This skill is the set of rules that catch that.

## When to use this

Writing or reviewing anything in a Next.js 14+ App Router project: pages, layouts,
components, route handlers, metadata, Tailwind classes.

## Server components are the default. Keep them that way.

`'use client'` is not a fix for a build error. Every time you add it, you move the
component *and its whole import subtree* into the browser bundle.

Add it only for: `useState`/`useEffect`/`useRef`, event handlers, browser APIs, or a
library that needs them. Anything else stays on the server.

**The pattern that keeps the boundary small** — a server page fetching data, handing a
serialised prop to a thin client leaf:

```tsx
// app/thing/[slug]/page.tsx  — server, no directive
import { getThing } from '@/lib/things';
import ThingChart from '@/components/ThingChart'; // 'use client' lives THERE

export default async function Page({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;              // params is a Promise in Next 15+
  const thing = await getThing(slug);
  if (!thing) notFound();
  return <ThingChart points={thing.points} />;
}
```

Push `'use client'` down to the leaf that needs it, never up to the page.

**Props crossing the boundary must be serialisable.** Functions, class instances,
`Date`, `Map`, `Set` and React components do not cross. Pass a slug and resolve the
component from a client-side registry on the other side.

## Data fetching

- `fetch` in a server component is cached and deduped. Two components fetching the same
  URL in one render make one request.
- `export const dynamic = 'force-static'` on a route handler that reads only local content.
- `export const revalidate = 3600` beats a hand-rolled cache.
- **Never fetch your own API route from a server component.** It is an HTTP round trip to
  yourself. Call the function the route handler calls.
- **Never fetch same-server data from a client component with a loading spinner.** Render
  it on the server; the data is already there. A skeleton for data the server could have
  inlined is a self-inflicted layout shift.

## Metadata

```tsx
export async function generateMetadata({ params }): Promise<Metadata> {
  const { slug } = await params;
  const thing = await getThing(slug);
  if (!thing) return {};
  return {
    title: thing.seoTitle,
    description: thing.seoDescription,
    alternates: { canonical: `https://example.com/thing/${slug}` },
    openGraph: { title: thing.seoTitle, images: [`/og/thing/${slug}.png`] },
  };
}

export function generateStaticParams() {
  return allSlugs.map((slug) => ({ slug }));
}
```

`generateMetadata` and the page body both run; shared work is deduped by the fetch cache,
so do not thread data between them manually.

## Tailwind v4, and what changed

**Configuration moved into CSS.** `@theme` in your stylesheet, not `theme.extend` in a
config file. A v3 config still works through the compat layer, but new tokens belong in
CSS.

**Opacity modifiers now compile to `color-mix`.** This is the good news: `bg-[var(--x)]/10`
works on an arbitrary CSS variable, which it could not in v3. Design tokens as CSS
variables plus opacity modifiers is now the idiomatic pattern.

**`transform` utilities are standalone.** In v3, `scale-105` implied `transform`. In v4
`scale`, `translate` and `rotate` are independent properties. So:

```html
<!-- broken in v4: transitions nothing -->
<div class="transition-transform hover:scale-105">

<!-- correct -->
<div class="transition-[scale] hover:scale-105">
<div class="transition-[scale,translate] hover:scale-105 hover:-translate-y-1">
```

This is the single most common silent v4 breakage: the hover still applies, it just snaps
instead of animating.

**Class names must be statically visible.** Tailwind scans source text. `` `bg-${c}-500` ``
generates nothing. Write full class strings and pick between them:

```tsx
const TONE = {
  ok:   'bg-green-500/10 text-green-600',
  warn: 'bg-amber-500/10 text-amber-600',
} as const;
```

**Default border colour changed** from `gray-200` to `currentColor`. A bare `border`
inherits text colour now. Always name the colour.

## Review checklist

- [ ] Is `'use client'` on the smallest component that needs it?
- [ ] Do all boundary props serialise?
- [ ] Is `params` awaited?
- [ ] Does every dynamic route have `generateStaticParams` where the set is known?
- [ ] Any interpolated Tailwind class names?
- [ ] Any `transition-transform` paired with a v4 standalone transform utility?
- [ ] Any client-side fetch of data the server already had?
- [ ] Any `border` without an explicit colour?
Versies

Wat er veranderd is

  1. v1.0.0huidig
    • Eerste versie: server versus client, data ophalen, metadata, en de Tailwind v4-verschillen.
    • Reviewchecklist van acht punten onderaan.

Werkt hij voor je?

Vragen

Over Next.js-conventies

Wat mensen vragen voordat ze hem installeren.

Zo een, maar dan voor jouw werk?

Elke skill hier komt uit werk dat ik echt deed. Zit er iets in jouw proces dat je telkens opnieuw uitlegt aan een agent, dan is dat precies een skill.