Design system

Forkluck visual guide: every component, rendered live

Every Forkluck component rendered live from the app's own code, with the design tokens behind it.

Forkluck
Butter croissant
On targetCosted 12 days agoPastryYields 24
Status

This page renders every component in Forkluck from the app's own code: the same files the kitchen screens import, on the same tokens, with nothing redrawn for the occasion. Everything is live, so hover, focus, and open the menus, popovers and modals. The design tokens behind all of it are at the end.

Page

Every screen is the same frame: the way back and a 24px title, then a toolbar of search, filters, a spacer and the actions, 16px above the content it filters. Every control in that row is 32px, and the one primary action sits last on the right.

Forkluck

Butter croissant

Components
Eight ingredients, one sub recipe

Flour, butter, milk, yeast, salt, sugar, egg wash, detrempe.

Yield
Per batch

48 pieces at 82 g, baked from a 24 hour cold ferment.

Section

A section is a card: rounded-xl over one hairline on the card fill, 20px of padding and 16px between the blocks inside it. There is no elevation anywhere in this design, so the hairline is the only edge. The metric card beside it is the same shell around a 26px figure.

Forkluck
Costing
Priced from the last delivery

Butter at $7.40 per kg carries 61% of the batch cost. The sheet yields 48 croissants at $0.79 each.

Food cost

28.4%

On target

Target 30% or under

Heading

Forkluck has no Heading component; a heading picks a step from the type scale. Four of the ten steps carry one: 24px for a page title, 17px for a dialog title or a section heading, 16px for a card heading, 14px for a list title. No step carries a line height of its own.

Forkluck
Butter croissant24px page title
Delete this recipe?17px dialog title
Costing16px card heading
Dry goods14px list title

Text

Forkluck has no Text component; tone is a colour token on the class. Body text is 13.5px ink, quieter lines step down through muted and faint rather than shrinking, and the semantic inks are one green, one red and one amber. Meta lines are 11.5px.

Forkluck

Baldor delivered 12 cases of butter on Monday.

Priced from the invoice, not the catalogue.

No photo on file

Cost fell 3.1% against last week

Two ingredients have no purchase price

Four invoice lines are still unmatched

Updated by the kitchen

Paragraph

Forkluck has no Paragraph component either. Because no type step carries a line height, prose opts into its own: body copy runs at 13.5px over 1.65, and help text at 12.5px over 1.55 in muted ink.

Forkluck

A recipe holds its components, its yield and the method the kitchen follows. Costing reads the last price paid for each ingredient, so a delivery that moved the price of butter moves the plate cost of every recipe that uses it.

Prices come from the most recent invoice line matched to the ingredient.

A link is the accent: brand blue that underlines on hover. Blue is otherwise reserved for data and selection, so running text is the one place it appears as a colour to read. The link button and the link badge wear the same ink on the shapes they belong to.

Unordered list

Forkluck has no List component. A list in content is list-disc pl-5 with a 4px gap between items, at body size in muted ink.

Forkluck
  • Laminate the dough in three single folds
  • Rest 30 minutes between folds
  • Proof at 26 C until doubled

Ordered list

The same idiom with list-decimal, and no component behind it either. The numbers are the browser's own.

Forkluck
  1. Weigh the detrempe and the butter block
  2. Lock the butter in and chill for an hour
  3. Roll, cut and shape 48 pieces

Button

Emphasis comes from the variant, never from the size: an ink fill for the one primary action, then outline, filled grey and ghost below it, with destructive outside the scale. Every button is rounded-lg and sits on the 24, 28, 32 and 36px rungs, icon buttons included, so a toolbar of mixed sizes shares one corner. Pending disables the button and leads with a 16px spinner while keeping the label.

Forkluck

Button group

Forkluck has no ButtonGroup component; a row of actions is an 8px gap with the primary last. A dialog footer and a toolbar's right cluster are the same row, which is why the two read alike.

Forkluck

Press button

A toggle is the button that stays down. It wears the outline button shell at 32px on rounded-lg, so it lines up with the buttons beside it, and pressed fills with grey rather than ink or the accent: a held control is a state, not the one action of the view. Click it.

Forkluck

Clickable

A card takes a render prop, so the whole surface can be one link. There is no shadow and no focus ring here: the hairline firms to line-strong under the cursor and turns ink on focus. Hover it, then tab into it.

Forkluck
Butter croissant
48 pieces per batch

The whole card is the link. Hover it, then focus it.

Pain au chocolat
Not clickable

The same shell without a destination.

Badge

Badges label, they never act, so they carry no accent and no ink fill. One height, 20px, in two shapes: the rounded-full metric badge at 12.5px and the rounded-md row chip at 11.5px, both taking the same one red, one green and one amber.

Forkluck
PackageDraft4.2%UnmatchedNo priceSub recipeArchived
CaseOn targetOver targetDry goods

The notice banner is a 48px amber strip on the warning fill over the warning border, with an outline action pinned right, and it sits between a screen's toolbar and its table. The save banner is the quieter rounded-xl strip above an editor that needs a decision. The third kind of feedback is the toast, an ink pill that says what happened once an action has landed.

Forkluck
Four invoice lines are not matched to an ingredient.

Butter is priced in two units. Which one should costing use?

Chip

A chip is the 20px rung of the control ladder: the badge's row size on rounded-md, the small grey tag at 11.5px, and the unit chip that sits inside a measure field. They label an amount or a tag and stay out of the accent.

Forkluck
CaseSub recipeDry goodsAllergen free

Clickable chip

A chip presses or removes, never both, because a button cannot sit inside a button. The pressable one carries aria-pressed and fills with ink when it is chosen; the removable one keeps its hairline and ends in a 12px X with a name of its own. Click one.

Forkluck
BaldorDry goods

Spinner

One ring, spun, whose stroke tracks its diameter: 16px inside a control, 32px standing in for a card, 80px for a whole page. A press that waits on the server shows the wait on the control that was pressed, and content about to be replaced dims behind a single mark instead of disappearing.

Forkluck
LoadingLoadingLoading
Loading recipes

48 recipes, costed on Monday. The numbers stay legible while the screen waits.

Butter croissant, Pain au chocolat, Kouign amann

Searching

Tooltip

The tooltip is the only floating element in this design that is not white: an ink pill at 12.5px with an arrow, 6px off its trigger. It names an icon button that has no label of its own. Hover it.

Forkluck

Avatar

An avatar is always rounded-full on the secondary grey, at 24, 32 or 36px, so it lines up with the buttons beside it in a toolbar or a row. Initials step down with the size and carry no colour of their own. A photo only swaps in once it has loaded, so the initials stay up until then.

Forkluck
FLHCSPHC

Thumbnail

The images Forkluck holds are invoice scans and attachments, and this is their tile: a square at 32, 48 or 64px, rounded-md over one hairline, cropped with object-cover so a column of them keeps one edge whatever shape the file is. Without a file it draws the same tile on the soft fill with a muted icon, named by the alt text.

Forkluck
Baldor invoice, scanned
sm, 32px
Baldor invoice, scanned
default, 48px
Baldor invoice, scanned
lg, 64px
No file

Image

Forkluck has no Image component. A picture in content is a plain img at rounded-lg over one hairline, cropped to the aspect ratio the layout gives it.

Forkluck
Baldor invoice, page 1, scanned

Icon

Icons are lucide, and there is no wrapper around them. Three sizes do all the work: 14px inside a button, 15px in a menu's check slot, 17px in a menu row, where the icon plus its gap is a structural 27px lane. Tone is a text colour token, and blue stays with data and selection.

Forkluck
14px in a button15px check slot17px menu row

Text field

Fields are 36px on rounded-md over an input hairline, squarer than the buttons beside them because a control you type into is not one you press. Hover firms the line to line-strong and focus turns it ink; there is no focus ring anywhere in this design. Help text sits under the field, and an invalid field reddens its border and its message. Click into one.

Forkluck

Shown on the prep sheet the kitchen prints.

Text area

The text area is the field's edges and states grown to hold wrapped text, on the same rounded-md corner and the same hairline. It sizes to its content rather than scrolling inside a fixed height.

Forkluck

The method prints with the recipe, so write it the way the kitchen reads it.

Number field

A quantity a cook steps up and down: batch size, yield, days of cover. The shell is the text field itself, 36px on rounded-md, with the 24px ghost icon button at each end, so a number and a name in one form draw the same edge at the same height. Click a stepper.

Forkluck

Money field

Money is a field with an affix: the dollar sign sits on the input's own 12px padding, never takes a click, and the field behind it stays the whole hit area. The call site pads the text past it, and a rate hangs its unit off the other end the same way.

Forkluck

Email field

An email address is the standard field: 36px tall, rounded-md, one hairline that firms to grey on hover and turns ink on focus. The label above it is 13px medium, eight pixels clear of the box. Click into one.

Forkluck

Password field

The same 36px box with type="password", so the browser handles masking and the design changes nothing. Help text sits under the field at 12.5px muted.

Forkluck

At least 10 characters. Used for the kitchen account, not the supplier portal.

URL field

A prefix goes in an InputAffix, which owns the 12px inset and the vertical centering and is never a click target. The field pads past it, so the whole box stays the hit area.

Forkluck
Supplier portal

Search field

Search is the 32px variant of the same field, so a toolbar's search and its buttons share one height and one corner. The 15px magnifier is the only chrome: the browser's own clear button is hidden, because it empties the box without telling the filter.

Forkluck

Select

The picker is 36px with a 13px chevron, and sm is the 32px toolbar size. Its list is the same popover surface as a menu: white, one hairline, rounded-lg, 6px under the trigger, with a 15px check slot every row reserves so picking one never shifts the list. Open it.

Forkluck
Purchase unit

Date field

A date is typed as YYYY-MM-DD and the trailing quiet button opens one month of the app's own calendar, never the operating system's. The calendar reads today in the kitchen's timezone, which is UTC here. Open it.

Forkluck

Date picker

One month grid: a filled ink circle on the selected day, a ring on today, and the whole cell as the hit area. The reporting period filter decorates the same grid with its range fills, and its presets sit beside it. Open it.

Forkluck

September 2026

SuMoTuWeThFrSa

Color field

A colour as a labelled field: the hex is the value, and a 16px rounded-sm swatch sits on the field's own inset. The swatch lane is a real button that opens the picker in a popover, so the affix keeps its contract and the field still takes a hex typed straight in. Open it.

Forkluck

Color picker

The swatches are the semantic and chart colours from globals.css, each a 24px rounded-md button carrying its hex as its name. The selected one wears the ink border every selected control here wears, and the hex field is the standard 36px input.

Forkluck

Drop zone

A dashed line-strong box on the soft fill, rounded-xl like every other surface, with the outline button as the pointer's affordance. The whole box is the hit area and answers Enter and Space, and the dashed line turns ink while files are over it.

Forkluck

Drop files here

PDF invoices, up to 5 MB each

No files chosen yet.

Checkbox

A 15px box on a grey edge, ink when it is on, because selection is ink here and blue stays with data. Partial selection shows a dash on the same ink fill, and an invalid box reddens with its label.

Forkluck

Choice list

One choice out of a short visible list is a radio group: a 16px circle on the field hairline with an ink dot when it is checked. Several choices at once is a group of checkboxes instead. Both sit in a fieldset with a 13px legend.

Forkluck
Costing basis
Include in the export

Switch

A switch is a setting that takes effect at once, not a value to save, so it carries the brand fill when it is on. The track is 20px tall, or 16px at sm for an inline row, and the hit area runs well past what is drawn.

Forkluck

Table

Rows are 48px over a light rule, the header 48px over the one border rule that separates it from the body, and there is no outer card: the two horizontal rules are the whole frame. Numbers are tabular and right aligned, a state is a row badge, and every row ends in the ghost actions button.

Forkluck
RecipeCost per unitMarginStatus
Butter croissant$1.1468%Costed
Pain au chocolat$1.4263%Costed
Almond frangipane$2.0654%Review
SupplierInvoices
No suppliers match this filter.

Divider

One hairline in the border token, horizontal or vertical. The field separator is the same rule with a word sitting on the background over it, for the or between two ways into a form.

Forkluck

Yield 24 croissants

Batch time 3 h 20 m

BakeryPastryLarder
or

Box

Forkluck has no generic Box component. A surface is a Card, rounded-xl over one hairline with 20px of padding, and a call site that needs less overrides the padding; a quiet panel inside one is bg-fill-soft or bg-secondary with no border at all.

Forkluck
Butter croissant
Updated this morning
Twelve components, costed from last week's invoices.
Tighter padding
The same surface with 12px of padding.
bg-fill-soft, the quiet panel
bg-secondary, the grey fill

Stack

Forkluck has no Stack component and shows the Tailwind idiom instead: flex flex-col with gap-2 for rows that belong together and gap-4 for blocks that do not. An action row is flex gap-2 with the primary button last.

Forkluck

Bread flour

European butter

Sea salt

Mix and rest

Laminate

Proof and bake

Grid

Forkluck has no Grid component either. A detail screen is grid gap-4 with md:grid-cols-[2fr_1fr], the wide column carrying the table and the narrow one the summary, stacking on a phone.

Forkluck
Components
Twelve ingredients and two preparations
The wide column carries the table on a detail screen.
Costing
Yield basis
The narrow column carries the summary.

Scroll box

A box that scrolls its own content instead of the page, for a long list inside a dialog or a popover. The call site sets the height; the bar is 6px of line-strong, rounded-full, and fades in while the box is hovered or scrolling.

Forkluck

Query container

Forkluck has no container component and uses Tailwind's @container directly: the toolbar stacks at narrow widths and turns into a row at @md, measuring the card it sits in rather than the viewport. Drag the window narrow to see it reflow.

Forkluck

Popover

The menu's chrome with free content inside it, for the things a list of rows cannot hold. Same white surface, same hairline, same rounded-lg, hanging 6px under its trigger, with 12px of padding instead of the menu's 6. Open it.

Forkluck

Rows are 36px, rounded-md, and a row that runs a command always carries a 17px icon: the icon plus its gap is a 27px lane, so two menus opened from neighbouring controls agree about where their labels begin. A row that picks a value is a check item and reserves the 15px check slot in the same lane. Open them.

Forkluck

Dialogs come in five widths set by size, sm at 470px by default, on the card's rounded-xl over one hairline. The scrim is the only depth in this design, since there are no shadows, and the confirm shape puts two equal buttons side by side so neither answer reads as the safe one. Open them.

Forkluck

Empty state

The empty card is rounded-xl over one hairline: a 17px heading, one line of prose at 46 characters wide, and up to two actions. An empty table keeps its rows instead and shows one 48px message row, so the table does not double in height while it waits.

Forkluck

No ingredients yet

Add the things you buy, then build recipes on top of them. An invoice import fills this list in one pass.

IngredientLast price
No ingredients match this search.

Number

Every figure the app prints is tabular, so a column of costs lines up on the decimal. The metric card is a 12.5px label over a 26px numeral with an optional delta pill, green when the move is the one the kitchen wanted and red when it is not; 42px is the hero numeral, and there is no pill at all when there is no baseline to compare against.

Forkluck

Food cost

31.4%

−7.1%

Against 33.8% the week before

Net sales

$18,420

+7.7%

Against $17,110 the week before

$1.14

Components
12
Yield
24
Batch cost
$27.36
Bread flour$4.20
European butter$18.75
Sea salt$0.41

Design tokens

The look is a short list of CSS custom properties, and the components read them by name rather than spelling values out. Two of them are worth saying plainly: there is no elevation anywhere, so every shadow token resolves to none, and there is no focus ring, because focus turns a control's border ink instead. Radius has five steps, type has ten, and a control stands on one of five heights.

TokenValueWhat it changes
--background#ffffffPage and card surface
--foreground#18181bBody ink, and the fill of a primary button
--muted-foreground#52525bSecondary text, labels, table cells that are not the subject
--faint#71717aPlaceholders, sub-lines, the unit affix inside a field
--ink-soft#3f3f46Table headers, and the hover step of the ink button
--border#e4e4e7Every hairline in the app: cards, tables, fields, popovers
--line-strong#c9c9cfThe firm-up on hover, and the dashed edge of a drop zone
--inputvar(--border)A field's edge, named so fields move together
--secondary#f4f4f5The grey pill fill, badges, menu hover
--secondary-strong#e4e4e7The pressed and hovered step of that grey
--fill-soft#fbfbfcTable row hover and inset panels
--brand#3273dcLinks, chart marks, selection. Never a button fill
--brand-fill#d8e4f7Progress fills and the solid half of a chart mark
--brand-tile#e7effbThe icon tile
--brand-selected#f6f9feThe fill of a selected card or row
--destructive#d92d20Destructive ink and the filled delete button
--destructive-fill#fef8f7The pale ground a red chip or banner sits on
--destructive-strong#b42318The hover step of that red
--success#2f7a4fA metric moving the right way
--success-fill#eaf4eeThe ground under a green chip
--warning#c8880cThe needs-attention icon and border ink
--warning-foreground#6b4708Yellow text, dark enough to read on its own fill
--warning-fill#fdf8ecThe banner and chip ground
--warning-border#f6e6bfThe banner's edge
--disabled-foreground#c9c9cfDisabled text and the inert status dot
--ringvar(--foreground)Nothing draws a ring. Focus turns the border ink
--radius-sm / md / lg / xl / 2xl4px, 6px, 10px, 14px, 18pxFields are md, buttons and popovers lg, surfaces xl
--shadow-2xs … --shadow-2xl0 0 #0000There is no elevation. Every shadow resolves to none
--text-2xs … --text-4xl11.5, 12.5, 13, 13.5, 14, 16, 17, 24, 26, 42pxTen steps and nothing between them
Control heights20, 24, 28, 32, 36pxBadges, xs, sm, default, lg. 32px is the toolbar hinge
--font-bodyInterOne face, loaded once in the root layout

All of these are CSS custom properties declared in app/globals.css, in one place, so a value moves once and every screen follows it. A name that reads var(--other) rather than a literal is saying that the two are the same colour on purpose.

The examples are not screenshots or a separate copy of the library. They are the deployed app's own components, imported by this page and rendered on the same tokens, so what you see here is what ships.

Forkluck is recipe costing and analysis for chefs: it prices a recipe from the invoices a kitchen already receives, and keeps that price current as the next ones arrive.