Customizing the card

Control how a Collection's cards look — one per place entries are drawn (feed, list rows, board cards, calendar events, gallery tiles), plus a card of its own for any preset. Property order, width, labels, icons, fonts, colors, stat rows, photo sizes, phone vs desktop layouts and value-based rules, with a live preview, without changing the data you track.


Every Collection has a card — the little block you see for each entry in your feed. You decide how that card looks: which Properties show, in what order, how wide, with what labels and icons. This is pure presentation — changing the card never changes the data you've logged.

One card per place it shows

A Collection doesn't have one card — it has one per place entries are drawn, and each is yours to design:

  • Card — the feed, your global Log, and the chat log feed. The everyday one.
  • List rows — rows in a List view.
  • Board cards — cards in a Board view.
  • Calendar events — the event box you open in a Calendar view.
  • Gallery tiles — tiles in a Gallery, Mosaic or Books view.

Open the Collection's Cards tab to see all five. Each row tells you where it stands:

  • Custom — you've designed this one.
  • Inherited — it follows something below it (a preset follows the Collection).
  • Default — nobody has touched it, so Kaizendex's own design for that place draws. It is never blank.

Pick a row to preview it, or press Edit JSON to design it. They don't copy each other — making your feed card red doesn't make your board cards red, because a board card starts from a design meant for a board column. The editor's Copy from… does it in one click when you actually want that.

You edit the everyday Card from the Properties tab too, right where you define your Properties. A live preview sits at the bottom and updates as you tweak.

Presets can look different

A Preset — a named template like "Kettlebell full body workout" — gets its own page: click it on the Collection's Presets tab. There you set its default values and give it its own version of any of the five cards. So a kettlebell session can show an editable sets table on the feed, a tighter card on a board, and whatever you like on a calendar — without changing anything for the rest of the Collection.

Only what you change is stored. Everything else follows the Collection, and a single view can still differ on top of that if you want it to.

Editing the JSON

Every Edit JSON button in a Collection opens the same document — its cards, its presets and its views together — and jumps straight to the part you pressed, with the path shown at the top. A Jump to… picker moves you anywhere else without closing, and This section only narrows the editor to the one card when the whole thing is more than you need.

Saving only writes the parts you actually changed, so editing a board card can't disturb a preset, and two devices editing different parts won't overwrite each other.

What you can change per field

Each Property row is kept clean — a drag handle, the field's icon, its name, and its default value. To change how a field looks on the card, open its settings panel: click the ⠿ drag handle on the left of the row (without dragging) and choose Adjust settings. A panel slides in from the right — the same place the app opens view settings. It holds:

  • Visibility on cardAlways show (the default), Hide when empty, or Always hide. Cards no longer hide empty fields automatically: with Always show, a field with no value yet still appears, with a quiet placeholder in place of the value — click it to fill the field right there on the card. Pick Hide when empty for fields you'd rather tuck away until they're filled, or Always hide to keep a field off the card entirely (it still stores data; it just never shows here). This is the same three-way choice as Visibility on this page on the entry page, but it only affects the card — the two are set independently.
  • Label style — how the field is labelled on the card:
    • Label — the field's name (e.g. "Calories"). The default.
    • Emoji — the Property's emoji instead of the name.
    • Icon — the Property's icon (see Field icons below).
    • No label — just the value, no label at all. Great for compact cards.
  • Position — where that label sits relative to the value: Above it, Before it, or After it. (Hidden when Label style is No label — there's nothing to place.)
  • Width — how many of the card's 12 columns the field spans, from 1/12 (narrow) to 12/12 (full row). Auto lets Kaizendex pick a sensible width.

Reorder fields by dragging the ⠿ handle on the left of any row — the card follows the same order. The handle also opens the row's menu on a plain click: Adjust settings and Delete property.

Some settings in this panel show a small ⓘ indicator when something else can change that value for some entries: a Preset with its own card ("Overridden for entries using preset…"), a conditional rule that can restyle the field per entry ("May change per entry"), or a different phone/desktop layout ("Different on mobile/desktop"). It's a heads-up, not a warning — the setting you see is still the default; certain entries may render differently.

Field icons

Every Property shows a small icon in its row (and at the top of its settings panel). Click it to change it: a picker opens with three tabs — Emoji, Icons (the full icon library, searchable by name), and Upload (drop in your own image or paste an image link). Pick a 🔥 or a flame icon for calories, a 🏃 for distance.

A custom icon is remembered for this Collection only. To show it on the card, set that field's Label style to Icon. Choose Remove in the picker to go back to the default icon for the field's kind.

The Title

The Title row is the headline of the card. It behaves like any other field — drag to reorder it, and open its ⠿ → Adjust settings panel to set its width, label style, and position, or hide it — but you can't delete it (every card has a title).

By default the Title leads with its icon sitting Before the entry name. Switch its label style to No label for a clean text-only headline, Above to stack the icon over the name, or Label to show a small "Title" caption beside it — exactly the controls a Text field has.

Its icon defaults to the Collection's icon but you can give the title its own — click the icon on the Title row and pick a different one. That doesn't change the Collection's icon. See Properties and the Title for how the title's text works.

Letting a long title wrap

A title stays on one line and trails off with an ellipsis when it doesn't fit. Give it maxLines and it wraps instead, growing the card to fit:

"fields": {
  "title": { "maxLines": 4 }
}

Four lines suits a board card of real task names; the most you can ask for is 24. This works on the web and on your phone, and if you've turned on Title editable on card the editor wraps with it — Return still saves, it never adds a new line.

Editing the title and emoji on the card

By default a card's title and emoji are read-only — tapping either one opens the entry. A card behaves like a view, so a stray tap never starts an edit or loses your place. You always edit an entry's title and emoji on its own entry page.

If you'd rather edit them right on the card, turn it on per Collection — open the Title row's settings (⠿ → Adjust settings) and use its two independent switches:

  • Title editable on card — lets you rename the entry by tapping its title right on the card.
  • Emoji editable on card — opens the emoji picker when you tap the emoji on the card.

Turn on either, both, or neither. (They map to editable and emojiEditable on the title field if you'd rather use Edit JSON.) With both on, you can still open an entry by clicking elsewhere on its card or using ⋯ → Open.

Editing on a card reads as plain text — click into a title or value and type, with no box or highlight appearing around it. An entry you haven't named shows the Collection's name as its title; edit it like any text, and your edits save immediately and are never reverted. If you want a subtle background wash on hover/focus to signal what's editable, opt in with "card": { "editHighlight": true } in Edit JSON.

Finer control with Edit JSON

The visual controls cover the everyday cases. For full control over how the card looks, click Edit JSON (below the Properties list, or Advanced — edit card JSON inside a field's settings panel) to open the card's complete layout as a document. Paste a layout, hit Apply, and it validates instantly — invalid values are rejected with a clear message pointing at exactly what's wrong. This is also how the AI assistant designs cards for you: just describe the card you want.

The visual controls and the JSON are the same document — a toggle in the panel and a line in the JSON edit the same thing, so nothing you set in one silently loses to the other. The one exception is the JSON-only power features (value-based rules, inline stat rows, and per-field fonts/colors): those can style a field beyond what the panel shows. When a field is affected, its settings panel shows a small notice — with Open JSON to see it, and Remove overrides to clear just that field's advanced styling (keeping its simple settings) so the panel controls take over again. This banner also flags when a Preset's own card overrides this field for the entries that use it (see A different card for each Preset) — the same information the per-setting ⓘ indicators surface at the individual-field level.

For the whole card (card), you can set:

  • background, foreground (text), accent, and border colors.
  • font — any of the app's fonts (e.g. geist, geist-mono, inter, space-grotesk, lora, jetbrains-mono).
  • fontSize — a base text size for the card.
  • padding, gap (space between fields), radius (corner rounding), borderWidth, and dividers (false hides the thin lines between every field at once).

For each field (under fields, by field name), you can set its font, fontSize, fontWeight, color, labelSize, labelColor, iconSize, align (left / center / right), padding, checkboxColor (for a True/false field), and divider (false removes the thin line before it) — each overrides the card-wide setting just for that field.

The title field also takes two on/off switches of its own — editable and emojiEditable — that let you rename the entry or change its emoji right on the card. See Editing the title and emoji on the card.

A Sub-entries field (a list like a dish's ingredients) takes three switches of its own that turn its compact list into a checklist or todo: subEntryHideEmoji (hide the repeated emoji on every row), subEntryEditableTitle (type each row's title right on the card — its menu moves to the right so a tap edits, not opens), and subEntryAddTypeId (set it to a Collection's id and + Add drops that kind instantly, skipping the "what kind?" search — the new row is ready to type, and Enter adds the next). All three are off by default. See Make it a todo list.

Two rules keep cards tidy and safe:

  • Sizes use names, not pixels. Font sizes are xs, sm, base, lg, xl, 2xl; spacing/radius are none, xs, sm, md, lg (and xl for radius); borders are none, thin, medium, thick. You can't accidentally make text 500px tall.
  • Colors are a hex code or a theme color. Use a fixed color like #16a34a, or a theme name like role:accent / role:muted-foreground so the card automatically follows your theme (and light/dark mode). A per-card color overrides your theme for that one card.
{
  "version": 1,
  "card": {
    "background": "#1a0b2e",
    "foreground": "#f5e6ff",
    "accent": "#c026d3",
    "font": "geist-mono",
    "radius": "xl",
    "borderWidth": "thick"
  },
  "fields": {
    "title": { "fontSize": "2xl", "align": "center", "editable": true, "emojiEditable": true },
    "calories_1": { "fontSize": "xl", "color": "#22d3ee", "labelColor": "role:accent" }
  }
}

Stat rows

Numbers can sit together in one tidy line — the "320 cal · 30 P · 12 C" strip you know from calorie apps. Add a group under a top-level groups key listing the fields it holds, and those fields render side by side in a single row instead of taking their own grid cells. Each field keeps its own styling.

Pair it with the stat look: set a number field's display to "stat" and its value renders big with its unit small and muted right beside it — 5.2 km, 10 cal. Set the field's label style to unit so the unit comes from the Property itself.

{
  "version": 1,
  "groups": {
    "macros": { "fields": ["calories_1", "protein_2", "carbs_3"], "order": 2, "span": 12 }
  },
  "fields": {
    "calories_1": { "display": "stat", "label": "unit" },
    "protein_2": { "display": "stat", "label": "unit" },
    "carbs_3": { "display": "stat", "label": "unit" }
  }
}

How a number reads

A number is stored one way and can read another. Pace lives as decimal minutes per kilometre, and 5.85 is arithmetically right and wrong to every runner alive — they read 5:51. Add a format to the field and the card prints it properly, without touching the stored value:

  • "plain" — the ordinary number (the default).
  • "pace" — decimal minutes become m:ss. 5.855:51.
  • "clock" — minutes become h:mm once they pass an hour. 951:35.
{
  "version": 1,
  "fields": {
    "pace_4": { "display": "stat", "format": "pace", "label": "unit" }
  }
}

It applies to read-only cells only — a field you can type into always shows you the number you'd be editing.

A stopwatch as a finished total

A Stopwatch field normally renders its live control, with start and pause. On a card for something already finished — last Tuesday's run — that's a button nobody wants. Set the field's display to "value" and it prints the total instead, as a plain figure you can style like any other number (and format works on it too). Leave display off and you keep the live control exactly as before.

{ "version": 1, "fields": { "duration_2": { "display": "value", "format": "clock" } } }

Photo sizes

An image field can render three ways via display: thumb (a small rounded square that sits nicely in a row — the classic food-photo look), cover (the photo fills its whole cell), or hero (a full-width banner across the card). Two companions fine-tune it: aspect ("auto", "square", "video", or "portrait") sets the shape, and fit ("cover" or "contain") decides whether the photo fills the shape or letterboxes inside it.

A GPS distance field (a recorded run) can also choose its look: "trace" draws the clean line, "map" draws it over a real street map.

Showing a Page on the card

A Page field is set to Always hide on the card by default — open the entry to read or write it. Turn it on from that field's ⠿ → Adjust settings (Visibility on cardAlways show) and it renders as a formatted preview: headings, bold, lists, and checklists look just like they do on the open entry, a few lines tall with a soft fade at the bottom and a See more when there's more to read.

Click anywhere in the text (or See more) to edit it right on the card. The full editor opens in place — type, delete, and use keyboard shortcuts for formatting — without any of the block handles or menus from the entry page. A very long Page scrolls inside the card instead of stretching it. See less tucks it back into the preview when you're done. For the complete editing experience (drag-to-reorder blocks, slash commands, images), open the entry.

A card can show more than one Page field.

Different layouts on phone and desktop

Any part of the card — the card itself, a field, a group, a button — can carry a mobile or desktop override: the same settings, applied only on that screen size. So a photo can be a big hero banner on your phone but a small thumb on a wide screen, or a field can drop to full width when the card gets narrow:

"fields": {
  "photo_5": { "display": "thumb", "mobile": { "display": "hero" } }
}

Cards that adapt to their own width

mobile and desktop ask how big your screen is. Sometimes the better question is how much room the card got — a board column is narrow even on a huge monitor. For that, use compact and regular, which work exactly the same way but key off the card's own width (under about 320 pixels counts as compact):

"fields": {
  "notes_2": { "maxLines": 6, "compact": { "maxLines": 2 } }
}

Reach for these when you're styling for a tight space — a board column, a gallery tile, a card tucked into a narrow dashboard slot. If a setting has both a desktop and a compact value, the compact one wins, because it's the more specific answer about the space the card actually has.

Rules that react to values

The conditional rules you've seen with buttons can now test values, not just whether a field is filled. A rule's when takes all (every condition must hold) and/or any (at least one must), each condition naming a field, an operator — eq, neq, gt, gte, lt, lte, contains, empty, present — and a value. And a matching rule can now restyle the whole card or a group, not just individual fields:

"rules": [
  {
    "when": { "all": [{ "key": "calories_1", "op": "gte", "value": 2000 }] },
    "card": { "accent": "role:success" }
  }
]

That's "when today's calories reach 2000, tint the card with my theme's success color". Hit a goal, see the card celebrate it.

The sets table

A Sub-entries field can render its children as an editable table — the gym-log look, but with no header row and no set numbers: each row leads with the exercise's emoji + name, then its values right after — each one showing its own label right beside it, so "12 reps" and "16 kg" read clearly without a column header naming them. Pick Sets table straight from the display dropdown on the Properties tab's Sub-entries row — no JSON needed — or set the field's subEntryMode to "table" via Edit JSON for full control. Either way you can pick which columns show (and their order) with subEntryColumns, listing the child fields by name. Type straight into the cells, and + Add appends a row ready to fill in.

Prefer the phone-friendly workout look? Pick Grouped sets instead: sets of the same exercise collapse under one heading (the name prints once), the column names print once per block, and every set is a numbered row whose values always fit the screen — no sideways scrolling, ever. The set number opens the row's menu, + set adds another set copied from the last, and the + Add control is a small text button bottom-left. Set subEntryMode to "grouped" in Edit JSON, or just pick it from the same display dropdown.

Prefer a lighter look? subEntryMode: "line" (List with values in the Properties dropdown) keeps one clean line per set — emoji, name, then the values with their units on the right (20 reps 12 kg), skipping anything that wasn't logged. Same subEntryColumns picks which values show. See Sub-entries for everything lists of children can do.

An expand button on your card

Give the card "expand": "page" inside its card block and it gains a small expand control (⤢) next to the card's menu. Tap it and the entry opens as its own full page — every property, its notes, its sub-entries, all with room to breathe.

Tapping the card itself already does this, so the button is really there for cards you've taught to do something else on tap (tick a todo, start a timer): it keeps the entry's page one tap away. Your browser's back button brings you straight back to where you were.

Buttons on your card

A card can also show a button — a tappable action, not just a value. Buttons are built the same closed, safe way as everything else on a card: you choose the label, icon, color, and where it sits, and Kaizendex supplies what it does from a short built-in list (today: record a route). There's no free-form code in a button — buttons stay in this closed vocabulary.

Nothing is ever added to your card for you. A GPS distance property already draws its own Start control as its cell (the way a Stopwatch property draws its own), so you don't need a button for that — see Recording runs. Add one only when you want the action somewhere else on the card, or with your own label and styling. You do it under a top-level actions key via Edit JSON:

{
  "version": 1,
  "fields": { "title": { "order": 0, "span": 12 }, "route": { "order": 2, "span": 12 } },
  "actions": {
    "track": {
      "action": "record_route",
      "target": "route",
      "label": "Start run",
      "order": 1,
      "span": 12
    }
  },
  "rules": [
    { "when": { "present": ["route"] }, "actions": { "track": { "visible": false } } }
  ]
}

target points at the GPS distance field the button should fill; the rules entry hides the button once that field has a value, using the same conditional rules as everything else on the card. Up to 8 buttons per card, each with its own label, icon, style (primary / outline / ghost), and the same size/color/placement controls as any field.

A card for your Board, a row for your List

The card you design here is your Collection's card — the one your Log and your Feed show. Two other views carry a design of their own, edited the same way through their view settings:

WhereWhat you're editingKept separate from your Log's card?
Board view → Edit card layout JSONthat board's cardsYes — its own design
List view → Edit row layout JSONthat list's rowsYes — its own design
Feed view → Edit card layout JSONtweaks on top of your Log's cardNo — it starts from it

A Board card and your Log's card are separate artifacts on purpose: they're different shapes, so restyling one must never quietly restyle the other. Until you customise it, each starts from a sensible layout worked out from your properties — and the editor opens on that real layout, so you're always editing the thing you can see rather than a blank page. Reset to default cards puts it back.

Board cards are narrow, so their starting layout leans compact: every field on its own full-width line, labels dropped where a value speaks for itself, a short clamped preview of any Page, and heavy things like photos and route maps switched off. Turn any of it back on — it's your document.

A different card for each Preset

Everything above styles a Collection's card as a whole. If you've set up Presets (named templates like "Kettlebell workout" inside a Workouts Collection — see Logging an entry), you can give each preset its own card instead of sharing the Collection's.

On the Collection's Presets tab, every preset row has a Edit card JSON button next to its name. Open it and you get the same layout document and validation as the Collection's own Edit JSON — style this one preset's card differently (a sets table for "Leg day", a photo-led layout for "Big breakfast") without touching the Collection's default card or any other preset. Leave it blank and the preset's entries just use the Collection's card, same as always.

Below the preset list, a Preview shows a live card built from that preset — its pre-filled values and sub-entries, styled with your override — so you see exactly what a new entry from that preset will look like before you log one.

Kaizendex knows which entries belong to which preset by the Category value it stamps on them when you instantiate the preset. The override is matched when the card renders, so every entry carrying that Category — past or future — shows the preset's card, and it's pure presentation: your logged data never changes. If you rename or delete the preset later, older entries keep their original Category value, stop matching, and simply fall back to the Collection's regular card.

A preset can also set the entry's title — give the preset its own default title and every entry it creates opens with that title already filled in; leave it blank and Kaizendex titles the entry with the preset's own name instead (so "Kettlebell full body workout" never logs as an untitled card).

In fact, a preset is exactly that: a set of default values for the Collection's Properties. Expanding a preset shows one row per Property, in the same order as the Properties tab — numbers and stopwatch/timer totals as number fields, text-shaped Properties (including a Page) as text fields, and tag Properties as a dropdown of that Property's tags. The Category dropdown defaults to the preset's own name (that's the stamp described above); pick a tag instead and your entries carry that tag — just note that per-preset card matching follows the Category value, so entries stamped with a different tag use the Collection's regular card.

Next