/ component

if() Conditional Value

Edit the CSS if() conditional value function (shipped 2025) with compile-time BRANCH-GRAMMAR validation. if() picks a value from a list of guarded branches: if( <condition> : <value> [ ; โ€ฆ ]* ), where each condition is media(), supports(), or style(), and the final branch may be a bare else. The strict tier validates the if() wrapper (via the kit's ParseFunction), splits the body on TOP-LEVEL semicolons (a local paren-aware splitter โ€” the kit ships none), splits each branch on its FIRST top-level colon (so a colon inside style(--x: 1) is not a split), checks the condition kind, enforces else-as-last-branch, and requires a non-empty value. Condition bodies are validated leniently (non-empty + balanced parens); the runtime parser does fuller structural work. if(foo(x): 1) โ†’ never (unknown kind); if(else: a; media(x): b) โ†’ never (else not last).

/ basic-usage

Branch by condition

Controlled value + onChange. The CSS if() function picks a value from a list of guarded branches โ€” each branch is a condition : value separated by semicolons, where the condition is media(), supports(), style(), or a trailing else. Add branches and the editor emits a valid if() string.

if(media(width >= 800px): 2rem; else: 1rem)
/ branch-builder

Build the branch list

Each row is one branch: a condition-kind select (media / supports / style), a condition-body input, and the value. Add or remove branches; the final row may switch to a trailing else. The produced if() string updates live.

:
:
(always):
if(media(width >= 800px): 2rem; supports(width: 1cqi): 1.5rem; else: 1rem)
preview
cutting-edge browser support
if() value

The CSS if() function shipped in 2025; support is still rolling out. Non-supporting browsers ignore the declaration and fall back.

produced value
if(media(width >= 800px): 2rem; supports(width: 1cqi): 1.5rem; else: 1rem)

Heads up: the CSS if() function is cutting-edge โ€” it shipped in 2025 and browser support is still rolling out. Non-supporting browsers ignore the declaration and fall back.

/ types

Three usage tiers

From useState-and-go to compile-time branch-grammar validation.

01 casual
string

Pass any string

useState<string>. No compile-time validation; the runtime parser splits the branches and classifies each condition โ€” including condition bodies the strict tier only checks for balance.

if(media(width >= 600px): grid; else: block)
const [value, setValue] = useState<string>("if(media(width >= 600px): grid; else: block)")
02 intellisense
IfFunctionString

Literal-shaped hints

State typed as IfFunctionString โ€” an if(โ€ฆ)-shaped string. It is also the onChange return type, so downstream consumers stay in the suggestion union.

if(supports(display: grid): grid; else: block)
const [value, setValue] = useState<IfFunctionString>("if(supports(display: grid): grid; else: block)")
03 strict
IfFunctionLiteral<S>

Branch grammar typed at compile time

cssIf() validates the if() wrapper, splits branches on top-level semicolons, splits each branch on its first top-level colon, and checks the condition kind, the else-last rule, and a non-empty value โ€” resolving any violation to never before you run the code.

if(media(width >= 800px): red; supports(color: oklch(0 0 0)): green; else: blue)
cssIf("if(media(width >= 800px): red; else: blue)") // โœ“
// @ts-expect-error unknown condition kind
cssIf("if(foo(x): 1)")
// @ts-expect-error else not last
cssIf("if(else: a; media(width >= 1px): b)")

Note: condition bodies (the media-query / supports-condition / style-query grammar) are validated leniently at the type level โ€” non-empty + balanced parens. The runtime parser does fuller structural work.

/ api

API

Public surface โ€” component props, runtime helpers, and the type exports.

ยง IfFunction / IfFunctionPanel

<IfFunction
  value: IfFunctionString | (string & {})
  onChange: (next: IfFunctionString) => void
  className?: string
  aria-label?: string
/>

IfFunction is popover-wrapped; IfFunctionPanel renders the same editor inline. Both are controlled.

PropTypeDescription
valueIfFunctionString | (string & {})Current CSS if() value. Required. An empty / unparseable value renders an empty branch list.
onChange(next: IfFunctionString) => voidFires when the branch list changes. Emits the canonical `if( b1; b2; โ€ฆ )` string.

ยง Sub-components

<BranchRow branch onChange onRemove allowElse? index? />

One editable branch: a condition-kind select, a condition-body input (hidden for `else`, which shows `(always)`), a value input, and a remove button. `allowElse` gates the `else` option (final row only).

<ConditionKindSelect label value onChange allowElse? />

A labelled native select over media / supports / style (+ else when allowElse).

<AddBranchButton onAdd />

Appends a fresh media branch via onAdd.

<IfPreview value />

Applies the built if() string to a sample element's color, with a cutting-edge browser-support caption and a graceful fallback.

ยง Runtime helpers

cssIf<S>(value: S & IfFunctionLiteral<S>): S

Call-site validator for if(). Mirrors color() / easing() / cssCalc().

parseIf(src): IfBranch[] | null

String โ†’ typed branches, or null on a bad wrapper / no branches / a branch without a top-level colon / an empty value / an unknown kind / an unbalanced body / else-not-last. Trailing and interior empty branches are tolerated.

formatIf(branches): string

Canonical re-serialization โ†’ `if( b1; b2; โ€ฆ )` (kind(condition): value, joined by `; `).

branchToCss(branch): string

One branch โ†’ `else: value` or `kind(condition): value`.

branchCount(src): number

Runtime mirror of BranchCountOf โ€” the branch count (invalid โ†’ 0).

defaultBranch(kind?): IfBranch

Seed a fresh branch (defaults to a media branch with a valid condition + value).

ยง Types

IfFunctionLiteral<S>
Strict validator โ€” S if S is a valid if() value (wrapper, branch split, condition kind, else-last, non-empty value), else never. Condition bodies validated leniently.
IfFunctionString
Suggestion union โ€” an if(โ€ฆ)-shaped string. The onChange return type.
ConditionString / ConditionKind
A single condition suggestion union (media()/supports()/style()/else) and the kind discriminant.
BranchesOf<S> / BranchCountOf<S>
Tuple of the raw per-branch strings; and its length.
ConditionKindsOf<S>
Tuple of each branch's condition kind.
IfBranch
Per-branch record { kind; condition; value }. Exported for advanced use.
IfFunctionState
{ branches: IfBranch[] } โ€” the internal editor state; `kind` is the per-branch discriminant.

ยง Strict-tier scope

  • The if( โ€ฆ ) wrapper is validated via the kit's ParseFunction (name must be if).
  • The body splits on top-level semicolons (a local paren-aware char-walk; the kit ships no semicolon splitter) into โ‰ฅ1 branch. A trailing ; is tolerated.
  • Each branch splits on its first top-level colon โ€” so a colon inside style(--x: 1) or a value's url(a:b) is not the split point.
  • The condition kind must be media() / supports() / style() or a literal else โ€” else permitted only as the last branch. The value must be non-empty.
  • Condition bodies are weak-validated (non-empty + balanced parens). The internal media-query / supports-condition / style-query grammar is deferred to the runtime parser (and the media-query builder component).
  • calc() / var() inside a body or value is opaque text โ€” accepted as long as parens balance and the slot is non-empty.
/ install

Drop it in

One command via the shadcn CLI.

$ pnpm dlx shadcn@latest add https://turtiesocks.github.io/ridiculous/r/if-function.json