Skip to content
Components

Approval stack

Who has to say yes, carried by icons and words — the full stack in a panel, one icon in a row.

Try it

buildingcouncilpublicstate

stackLabel() → "Building + council"

Code
<GdApprovalStack :required="parcel.approvals" />

import { stackFor, stackLabel, APPROVAL_ORDER } from "@gridd/ui/approvals"

stackLabel(["building", "council"])   // "Building + council"
stackLabel([])                        // "No approval needed"

Inline

A garden shed
A granny flat
A six-unit development
Code
<GdListRow title="A granny flat">
  <template #sub>
    <GdApprovalStack inline :required="['building', 'council']" />
  </template>
</GdListRow>

API

Props

PropTypeDefault
requiredreadonly ApprovalAuthority[][]

The authorities this work needs, in any order — the component sorts them into the fixed one. Empty means no approval needed, and renders as such.

inlineboolean—

Collapse to a single 13px icon and label, for a list row, a table cell or a chip. The HIGHEST authority wins the slot.

iconsOnlyboolean—

Hide the words. Only where a label is already adjacent — the verdict banner puts its own title beside the stack.

sizenumber26

Tile edge in pixels. The glyph inside is drawn at 0.54 of it. Ignored when `inline`, whose icon is always 13px.

Slots

default

Replaces the generated label. The icons keep their own accessible name either way.

Usage Guidelines

  • Use the full stack in a panel, a verdict banner or a result — anywhere the reader is being told the answer rather than scanning for one.
  • Use inline in a list row, a table cell or a chip, where the stack is one attribute of many and only the hardest authority matters.
  • Use iconsOnly only when a label is already adjacent. On its own it is a row of glyphs with no answer beside them.
  • Pass an empty required rather than hiding the component — "No approval needed" is an answer, and the absence of a stack is not.
  • Reach for stackLabel() when you need the verdict as text — a page title, an email subject, a report line.
  • Do not sort or re-order required. Pass it in whatever order you have it; the component puts it in the fixed one.
  • Do not colour the tiles. If a status needs saying, it is a status message beside the stack, not a tint on it.

Behavior & Anatomy

Why icons rather than colour

Encoding a planning outcome in HUE is the obvious move and it fails the moment colour has to do anything else. If green means accepted development and red means impact assessable, then a failed network request drawn in the app's error red reads as an impact-assessable verdict, and a success toast reads as a planning approval.

So the two are split. Status colour is generic and means what it means in any product. What approvals a property needs is CONTENT, and it is carried here — in neutral ink, legible in pure greyscale.

The order, and the empty case

Turn everything off and the stack collapses to "No approval needed" on its own. That is not a special case in the template — stackFor() returns it, because "no approval" is the absence of the others rather than a fifth authority, and it never stacks.

Showing building for something that also needs public notice would understate it, which is why the inline choice is "highest" rather than "first".

  • Fixed order, always: building → council → public notification → state. The stack reads left to right as "and then", so it is not a sort key.
  • "No approval" never stacks.
  • Tiles are 26px, neutral ink, side by side with a 4px gap — never overlapped, so every authority stays fully legible.
  • Icons are never coloured. The words beside the stack carry the verdict.
  • One accessible name for the whole stack. Announcing four icon names in sequence gives a screen-reader user the parts and not the answer.

Navigate

Esc