Skip to content
Get the beta

Search the docs

Start with the beta
Installation
Build your first page
Thinking in Turtlekit
Apps, websites and embeds
Components or native elements
Colour
Typography
Layout
Spacing, icons and shape
Components
Root
Layout
Typography
Code block
Button
Icon button
Button group
Call to action
Toolbar
Field
Text field
Text area
Select
Combobox
Date input
Save bar
Newsletter signup
File upload
Calendar
One-time code
Checkbox
Radio group
Switch
Segmented control
Toggle
Slider
Badge
Card
Data list
Item
Icon tile
Num
Time
Metric
Accordion
FAQ
Avatar
Media
Scroll area
Resizable
Carousel
Image slider
Logo cloud
Testimonials
Table
Data table
Chart
Site header
Site footer
Tabs
Page header
Breadcrumb
Pagination
Sidebar
Navigation menu
Callout
Error summary
Toast
Empty state
Skeleton
Progress
Spinner
Tooltip
Dialog
Popover
Hover card
Dropdown menu
Context menu
Menubar
Command
Elements area
Visually hidden
Error boundary
Design rules
Staying within the kit
Layout
Icons
Images and media
Typography
Readability
Colour
Composition
Accessibility
Elements
Motion
Interaction
AI pitfalls
Pricing
React design patterns
Single responsibility in React components
Presentational and container components in React
Children, function children and render props in React
The variant pattern in React
Compound components in React
Higher-order components in React
State colocation in React
Lifting state up in React
Deriving state during render
One status instead of many booleans
Adjusting state when a prop changes
Reading context with use() in React 19
Context selectors in React
Custom hooks and hook composition in React
One effect per concern in React
The latest ref pattern in React
Effect Events with useEffectEvent in React
Detecting the first render in React
Exposing methods with useImperativeHandle in React
Debouncing input in React
useDeferredValue in React
Loading components on demand in React
Virtualising long lists in React
Guard clauses and early returns in React
Skeleton placeholders in React
Rendering partial data in React
Empty states in React
Error boundaries in React
Reading async data with use() and Suspense in React
useTransition and Actions in React
Optimistic UI updates with useOptimistic
useActionState and form Actions in React
useSyncExternalStore in React
Ref as a prop and ref cleanup in React 19
Accessible ids with useId in React
Portals in React
Roving focus and keyboard navigation in React
Controlled and uncontrolled components in React
The state reducer and prop getters in React
Headless components and the provider pattern in React
The polymorphic as prop in React

Appearance

These change every page and preview on this site.

Turtlekit Editorial

React design patterns

React patterns built step by step on real product screens, with the engineering decisions behind each one.

Composition

How components fit together, and who owns the state and the layout.

Single responsibility

One reason to change per component, so a wording fix, an API change and a new action each land in one place.

Presentational and container components

Split how a list looks from what it knows, so the same component serves a server page and a picker dialog.

Children, function children and render props

Elements for what the page knows, functions for what the component knows, so a shared list stops branching.

The variant pattern

A closed set of named variants in place of styling props, so a status looks the same on every screen.

Compound components

Parts that share state through context, so each page arranges the layout while the parent keeps it wired.

Higher-order components

When a function that wraps a component still fits, and how to write one that hides nothing from its callers.

State

Where state should live, and what to compute instead of storing.

State colocation

Keep state in the lowest component that reads it, so typing in one box never re-renders the whole page.

Lifting state up

When two components must agree, move the state to their closest common parent and pass it down as props.

Deriving state during render

Compute what you can from props and state during render, so totals and selections never fall out of step.

One status instead of many booleans

Replace loading, error and success flags with one status value, so impossible combinations can’t render.

Adjusting state when a prop changes

Reset or adjust state when a prop changes without an effect: compute it, key it, or adjust during render.

Reading context with use()

React 19’s use() reads context after an early return or inside a branch, where useContext can’t go.

Context selectors

Let each component subscribe to the slice of shared state it reads, so one busy value doesn’t re-render all.

Hooks, effects and refs

Reusable behaviour, and effects and refs that stay correct as the code changes.

Custom hooks and hook composition

Write shared behaviour once as small hooks that compose, so two screens can’t drift apart while each keeps its own state.

One effect per concern

Give each effect one job and its own dependencies, so typing in a field never reconnects a subscription or logs a view.

The latest ref pattern

Keep the newest value in a ref, so a timer or listener that starts once reads current props without restarting.

useEffectEvent

Read the latest props and state from an effect without restarting it, with React 19.2’s useEffectEvent and its rules.

Detecting the first render

Why a first-render flag breaks in Strict Mode, and the initializer, handler or effect that answers the real question.

useImperativeHandle

Give a parent one small method, such as focus, instead of DOM nodes or a prop to toggle, with React 19’s ref as a prop.

Rendering and performance

Keeping input responsive and pages light, measured before it is optimised.

Debouncing input

Wait for a pause in typing before you search, and cancel the stale request, so a name sends one request.

useDeferredValue

Let the field render first and a slow table catch up in a render React can interrupt, with no delay to tune.

Loading components on demand

Keep code people may never use out of the first download with lazy and Suspense, and fetch it on intent.

Virtualising long lists

Render only the rows in view, keep the scrollbar true, and answer for screen readers and find-in-page.

Loading, empty and error states

The states every screen has besides the happy one, designed rather than left to chance.

Guard clauses and early returns

Return early for each case that ends a render, so the happy path reads flat and TypeScript knows what it holds.

Skeleton placeholders

Hold the space content will take with placeholders in its own shape, so nothing moves when the data arrives.

Rendering the data you have

Let only the data a section can’t do without decide whether it renders, and give every optional part its fallback.

Empty states

Say why a list is empty and offer the next step, and never let a failed load pass for an empty list.

Error boundaries

Keep one section’s crash inside that section, with a fallback that says what still works and keeps focus.

Async data and Actions

Reading async data and changing it, with React 19's Actions, Suspense and optimistic updates.

use() and Suspense

Start the request where the decision is made, read the promise with use(), and let Suspense and a boundary hold the wait and the failure.

useTransition and Actions

Keep the current screen while the next one loads, and let an async Action stay pending until its request settles, with no flags of your own.

Optimistic UI updates

Show an action’s result at once, let React 19 settle it, and roll back with a clear message on failure.

useActionState and form Actions

Let each form submission return the form’s next state, so errors, typed values and the pending state can’t drift apart.

useSyncExternalStore

Read a value React doesn’t own, such as localStorage, so every component shows the same one and other tabs follow.

Focus and the DOM

Reaching real elements: refs, ids, portals and the keyboard paths between them.

Refs in React 19

Pass ref as a plain prop instead of forwardRef, and let a ref callback return its own cleanup, as React 19 allows.

Accessible ids with useId

Tie labels, hints and errors to their fields with ids that are unique on the page and match from server to browser.

Portals

Draw part of a component somewhere else in the DOM while React keeps it where it belongs, and know which tree each rule follows.

Roving focus

Make a toolbar or tab list one Tab stop, with the arrow keys, Home and End moving inside it, mirrored right to left.

Component APIs

What a component hands the people who use it: control of its state, its logic and its markup.

Controlled and uncontrolled components

Decide who owns a component’s value: the parent, through value and onValueChange, or the component itself, from a defaultValue.

State reducer and prop getters

Let the code that uses a hook have the last word on each change and own the markup, while the hook keeps the mechanics.

Headless components and providers

Share behaviour without markup so each screen draws it its own way, and give what is true for a whole account once, from a provider.

The polymorphic as prop

Let a component render the element a call asks for, from a closed list, with the props, events and ref of that element.