Expense form

The composer is the core of Settld. "Log a โ‚น4,200 dinner in 5 seconds" is not a tagline โ€” it's the spec. Five rows, frosted glass, a coral margin rule down the left. Every row is a self-contained decision: where, how much, who, how to split.

Composed view

๐Ÿœ
Where
Farzi Cafe
โ‚น
Amount
โ‚น4,200
๐Ÿ‘ฅ
Y
You
A
Aarav
P
Priya
R
Rohan
โ‡Œ
Split
Result
Youโ‚น1,400
Aaravโ‚น1,400
Priyaโ‚น1,400

The composer is a frosted glass card โ€” backdrop-filter: blur(16px) saturate(1.1) โ€” placed against a warm surface so the blur has material to work with. On a white background it's invisible; always layer it over the canvas or a section bg.

The coral margin rule is a 1px vertical line at left: 56px โ€” the exact width of the icon column. It runs the full height of the card with opacity: 0.22. This is the khata ledger aesthetic: a physical notebook margin, not a UI chrome element.

Row anatomy

Row 1 โ€” Where Emoji category glyph + text input. The emoji is not decoration โ€” it communicates the expense category at a glance. Use ๐Ÿœ (food), โœˆ๏ธŽ (travel), โŒ‚ (home) as the default three. Plain-text placeholder: "What was this for?" โ€” no label that says "Enter description".
Row 2 โ€” Amount JetBrains Mono 28px, โ‚น as a muted prefix (18px, --ink-mute). No thousands separators while typing โ€” add them on blur. The amount field is the row; no extra chrome around it. Tapping anywhere in the row focuses the field.
Row 3 โ€” With Person chips in a wrapping flex row. Selected chips use --teal-pale fill + --teal border and text. Unselected chips are paper with hairline border. The "You" chip is always first and always selected โ€” it cannot be removed. Chip tap toggles inclusion; if a chip is deselected, re-run the split calculation.
Row 4 โ€” Split mode Segmented control with four options: Equal, Unequal, %, Shares. Active segment gets a paper fill + shadow. The active pill does not animate between options โ€” it's an instant snap, not a sliding underline. The pill itself is the affordance.
Row 5 โ€” Result The split bar shows proportional segments, one color per person (using avatar palette). Below it, a flex row of person + amount pairs in mono. This row is read-only on Equal mode; on Unequal/Shares it becomes editable inline. The total must always equal the amount entered in Row 2 โ€” validate in real-time.

Split modes

Equal
โ‚น4,200 รท 3 = โ‚น1,400 each. Remainder of odd splits always goes to the person who paid.
Unequal
Each person gets a direct โ‚น amount input. Bar resizes live. Total must equal the original amount.
Percentage
Percentages must sum to 100. Show live remainder "12% remaining" in mono when not 100%.
Shares
Integer share counts. 2 shares = double the single-share amount. Good for hotel rooms where some got a balcony.

Dashed dividers

Between-row dividers use border-bottom: 1px dashed var(--ink-line). Dashed, not solid. This is intentional โ€” it's the ledger / khata language, not a separator. Solid dividers would feel like a table; dashed dividers feel like ruled paper with content waiting to be filled in.

The only solid border in the composer is the outer card border and the submit row's top separator. Everything internal is dashed.

Empty and error states

Empty
๐Ÿœ
Where
What was this for?
โ‚น
Amount
โ‚น0
Validation error
โ‚น
Amount โ€” percentages must total 100%
โ‚น4,200

Empty state: the Add expense button is disabled until both a description and a non-zero amount are present. Don't show red states before the user has tried to submit โ€” validate on submit, not on blur, for the first interaction. After a failed submit, switch to on-change validation.

Validation errors use coral border on the entire card (not per-field outlines) and a coral error message in the label position. The button switches to coral fill โ€” it's still tappable, but the error is visible. Never block the submit button silently; if there's an error, show it at the same moment you block submission.

Usage

Do Always show the result row, even for equal splits โ€” it builds confidence that the math is right. Show โ‚น amounts per person, not just percentages.
Don't Don't hide the split bar when there's only one person. It communicates "this is an expense, not a payment."
Do Maintain the 56px icon column โ€” it's the vertical margin rule anchor. If the column width changes, the coral margin line misaligns.
Don't Don't add more rows to the composer. Five rows is the ceiling. Additional data (notes, photos, recurring) go in an expandable "more" section below the submit row.

Code

Composer shell

<!-- Glass card shell โ€” always on a non-white bg -->
<div class="composer">

  <!-- Each row: icon-column + field -->
  <div class="composer-row">
    <div class="composer-icon">๐Ÿœ</div>
    <div class="composer-field">
      <div class="composer-label">Where</div>
      <input class="composer-value" placeholder="What was this for?">
    </div>
  </div>

  <!-- Amount row -->
  <div class="composer-row">
    <div class="composer-icon">โ‚น</div>
    <div class="composer-field">
      <div class="composer-label">Amount</div>
      <div class="composer-amount">
        <span class="currency">โ‚น</span>
        <input type="number" inputmode="decimal" value="0">
      </div>
    </div>
  </div>

</div>

Design tokens used

TokenValueRole in composer
--glass-bgrgba(251,248,240,0.72)Card background
--glass-borderrgba(255,255,255,0.55)Card border
--r-xl28pxCard corner radius
--coral#E76F51Margin rule, error state
--ink-line#DDD2B8Dashed row dividers
--teal-pale#D6EAE2Selected chip fill
--s-deep#E8DEC5Segmented control track
--d-slow420msSplit bar transition
--ease-springcubic-bezier(0.34,1.56,0.64,1)Split bar easing