Calc Editor
Edit a CSS math expression โ calc(), clamp(), min(), max(), nested โ with compile-time DIMENSIONAL ANALYSIS. length ยฑ length โ, length ยฑ angle โ, length ร length โ, รท by non-number โ. The strict tier resolves invalid math to never.
Edit a calc value
Controlled value + onChange. The popover editor parses, dimension-checks, and only emits a valid CSS math string.
clamp(1rem, 0.5rem + 2vw, 3rem)clamp() across the viewport
Drag the viewport slider and watch the computed font-size resolve live. This is fluid typography โ a single clamp() that scales between a min and max as the screen grows.
- 320px
- 18.4px
- 768px
- 27.36px
- 1440px
- 40px
The quick brown fox
Three usage tiers
From useState-and-go to literal-validated dimensional algebra.
Pass any string
useState<string>. No compile-time validation; the runtime parser handles whatever you type.
calc(100% - 2rem)const [value, setValue] = useState<string>("calc(100% - 2rem)")
Literal-shaped hints
State typed as CalcString โ the calc() / clamp() / min() / max() union. Also the onChange return.
min(50%, 30rem)const [value, setValue] = useState<CalcString>("min(50%, 30rem)")
Dimensional algebra at compile time
cssCalc() resolves invalid math to never. Mismatched units type- error before you ever run the code.
calc(10px + 2rem)cssCalc("calc(10px + 2rem)") // โ length // @ts-expect-error length + angle cssCalc("calc(10px + 45deg)") // @ts-expect-error length ร length cssCalc("calc(10px * 2px)")
Note: var() is undecidable at compile time โ use the casual or IntelliSense tier for expressions containing it.
API
Public surface โ component props, runtime helpers, and the type exports.
ยง CalcEditor / CalcEditorPanel
<CalcEditor
value: CalcString | (string & {})
onChange: (next: CalcString) => void
fn?: 'calc' | 'clamp' | 'min' | 'max'
referenceViewport?: number
className?: string
aria-label?: string
/>CalcEditor is popover-wrapped; CalcEditorPanel renders the same editor inline. Both are controlled.
| Prop | Type | Description |
|---|---|---|
| value | CalcString | (string & {}) | Current CSS math expression. Required. |
| onChange | (next) => void | Fires only when the edited expression is dimensionally valid. Return type narrows by `fn`. |
| fn | CalcFn? | Lock the outer function to calc/clamp/min/max. Narrows onChange to that flavor. |
| referenceViewport | number | Viewport width (px) for the computed-value readout. Default 1280. |
ยง Sub-components
<ExpressionField value onChange dimension? error? />
The text field + live validity/dimension badge.
<TokenPalette onInsert />
Click-to-insert operators, units, functions, and var().
<FluidTypePlayground expression minViewport? maxViewport? />
Viewport-width slider with a live computeCalc readout โ the clamp() showcase.
ยง Runtime helpers
cssCalc<S extends string>(value: S & CalcLiteral<S>): S
Call-site validator. Mirrors color() and easing().
parseCalc(src: string): CalcNode | null
String โ AST, or null on any syntax error.
evaluateCalc(src: string): { node, dimension, error }Parse + dimension-check facade the editor calls each keystroke.
calcDimension(node: CalcNode): Dimension | null
Resolve an AST to its dimension, or null on a unit conflict. var()-tolerant.
computeCalc(node, ctx): number | null
Numeric evaluation resolving px/rem/vw/% against a ComputeContext. Null when var() blocks it.
formatCalc(node: CalcNode): CalcString
Canonical re-serialization (normalized spacing).
tokenizeCalc(src: string): Token[]
Lexer โ numbers (with units), idents, operators, parens, commas.
ยง Types
- CalcLiteral<S>
- Strict validator โ S if dimensionally valid, else never.
- CalcString
- Suggestion union: calc()/clamp()/min()/max().
- CalcStringMap / CalcFn
- Function โ output-string map for `fn` narrowing.
- FunctionOf<S>
- Outer function family of a literal.
- DimensionOfCalc<S>
- Resolved dimension of a literal at the type level.
- ArgCountOf<S>
- Top-level comma-argument count of the outer function.
- CalcNode
- Parse-tree discriminated union (exported for advanced use).
ยง Strict-tier scope
- Full dimensional algebra:
+ -require equal dimensions;*needs a number operand;/needs a number divisor.%is its own dimension. - Evaluation is right-associative at the type level โ dimensionally lossless. The runtime parser applies real
* /precedence for the computed value. - Nesting is depth-capped at 8 levels (weak-accept beyond); the runtime parser is uncapped.
var()is undecidable at compile time, so the strict tier rejects it. The runtime treats it as dimension-agnostic โ use the casual / IntelliSense tier forvar()expressions.
Drop it in
One command via the shadcn CLI.
$ pnpm dlx shadcn@latest add https://turtiesocks.github.io/ridiculous/r/calc-editor.json