Cache Control Input

Reads back who will store a response and for how long, so a per-user page isn't cached by the CDN and HTML isn't stuck for days.

StopsPrivate page cached by the CDN

Installation

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/cache-control-input.json

The files land in your project. They're yours to edit.

Usage

cache-control-input-usage.tsx
import { CacheControlInput } from "@/components/ui/cache-control-input"

return <CacheControlInput defaultValue={accountPage} defaultPath="/account" defaultPersonalized now={Date.UTC(2026, 9, 14)} />

What it catches

  • Personalised pages that a CDN or shared cache may store
  • Responses that set a cookie but are marked public
  • no-cache used where no-store was meant
  • immutable on URLs without a content hash, and long max-age on HTML
  • A missing Vary for compressed or negotiated bodies; one-tap fixes for each

Props

CacheControlInput props
PropTypeDefault
value

Controlled header text: full "Name: value" lines, or a bare Cache-Control value.

string—
defaultValue

Initial header text when uncontrolled.

string""
onValueChange

Called with the new text on every edit or fix.

(value: string) => void—
personalized

Controlled "different for each signed-in user" switch.

boolean—
defaultPersonalized

Initial value of that switch when uncontrolled.

booleanfalse
onPersonalizedChange

Called when the user flips the switch.

(personalized: boolean) => void—
path

Controlled URL path the headers are for. Judges fingerprinted assets and HTML pages.

string—
defaultPath

Initial URL path when uncontrolled.

string""
onPathChange

Called when the user edits the path.

(path: string) => void—
varyOn

Request headers that change the body (e.g. ["Accept-Language"]); each must be listed in Vary.

string[]—
now

Clock for Expires maths, in ms. Defaults to the time the component mounted.

number—
label

Visible label; shorthand for `messages.label`.

string—
messages

Every visible string. `{detail}`, `{source}`, `{duration}`, `{swr}`, `{from}`, `{to}`, `{count}` are filled in.

Partial<CacheControlInputMessages>—

* required. Also accepts the native props of <textarea> (className, aria-*, data-*…), passed through to it.

Accessibility

  • Labelled textarea with aria-invalid and aria-describedby to a role="status" summary
  • Readback is a section labelled by its heading
  • After a fix, focus moves to the next fix button or back to the field
  • Severity is shown with icons and text, not colour alone

Only what the source does. Test with your own screen reader and content before shipping.

Limitations

  • Reads the header text you give it; real CDN behaviour also depends on its own configuration
  • Whether a page is personalised and the URL path are inputs you provide
  • Vendor-specific headers beyond CDN-Cache-Control and Surrogate-Control are not modelled

Rules

Rules last verified:

Informational; check the official source and your CDN's documentation. Surrogate-Control handling follows vendor convention and was not checked against a standard. Copied components don't update themselves, so re-check after rule changes (see updating a component).

What it stops

Private page cached by the CDN

Also known as

cache-control · http headers · cdn · cloudflare · vercel · s-maxage · max-age · immutable

Field type

Dependencies

Pairs well with