LogIt

Widget primitives

Every WidgetView.body entry is one of these. The previews below are rendered by the same logic the app uses.

text

A line of copy. tone: default · muted · primary.

3 workouts this week — one short of your target.

{
  "kind": "text",
  "text": "3 workouts this week — one short of your target.",
  "tone": "muted"
}

stat-grid

Up to three headline numbers.

12,480 kg

This week

48

Sets

2

PRs

{
  "kind": "stat-grid",
  "stats": [
    {
      "label": "This week",
      "value": "12,480 kg"
    },
    {
      "label": "Sets",
      "value": "48"
    },
    {
      "label": "PRs",
      "value": "2"
    }
  ]
}

list

Rows with an optional sublabel, trailing text, and a tap action.

  • Mon 31 Aug

    Top: Bench 3×80

    42m
  • Fri 28 Aug

    Top: Squat 5×100

    51m
{
  "kind": "list",
  "items": [
    {
      "label": "Mon 31 Aug",
      "sublabel": "Top: Bench 3×80",
      "trailing": "42m",
      "action": {
        "navigate": "/sessions/x"
      }
    },
    {
      "label": "Fri 28 Aug",
      "sublabel": "Top: Squat 5×100",
      "trailing": "51m",
      "action": {
        "navigate": "/sessions/y"
      }
    }
  ],
  "emptyText": "No sessions yet."
}

progress-rings

One ring per target.

Calories
Protein
{
  "kind": "progress-rings",
  "rings": [
    {
      "label": "Calories",
      "value": 1450,
      "max": 2200,
      "unit": "kcal"
    },
    {
      "label": "Protein",
      "value": 90,
      "max": 160,
      "unit": "g"
    }
  ]
}

bar

Horizontal bars. sublabel overrides the value text; tone: primary · protein · carbs · fat.

Calories 1450 / 2200 kcal
Protein 90 / 160 g
Carbs 140 / 240 g
Fat 55 / 70 g
{
  "kind": "bar",
  "bars": [
    {
      "label": "Calories",
      "value": 1450,
      "max": 2200,
      "sublabel": "1450 / 2200 kcal",
      "tone": "primary"
    },
    {
      "label": "Protein",
      "value": 90,
      "max": 160,
      "sublabel": "90 / 160 g",
      "tone": "protein"
    },
    {
      "label": "Carbs",
      "value": 140,
      "max": 240,
      "sublabel": "140 / 240 g",
      "tone": "carbs"
    },
    {
      "label": "Fat",
      "value": 55,
      "max": 70,
      "sublabel": "55 / 70 g",
      "tone": "fat"
    }
  ]
}

line

A trend line with an optional horizontal reference (e.g. a goal weight).

{
  "kind": "line",
  "reference": 78,
  "points": [
    {
      "x": 0,
      "y": 82
    },
    {
      "x": 1,
      "y": 81.4
    },
    {
      "x": 2,
      "y": 81
    },
    {
      "x": 3,
      "y": 80.6
    },
    {
      "x": 4,
      "y": 80.1
    },
    {
      "x": 5,
      "y": 79.6
    },
    {
      "x": 6,
      "y": 79.2
    }
  ]
}

muscle-map

A front/back body map. values is effort per muscle group; scale is the three band thresholds (default [1, 5, 12]).

{
  "kind": "muscle-map",
  "scale": [
    1,
    5,
    12
  ],
  "values": {
    "chest": 14,
    "triceps": 7,
    "shoulders": 4,
    "back": 2,
    "biceps": 1
  }
}

calendar-heatmap

A month grid; days are the days with activity.

{
  "kind": "calendar-heatmap",
  "month": "2026-09",
  "days": [
    {
      "day": 2
    },
    {
      "day": 4
    },
    {
      "day": 7
    },
    {
      "day": 9
    },
    {
      "day": 12
    },
    {
      "day": 15
    },
    {
      "day": 18
    },
    {
      "day": 21
    }
  ]
}

button-row

Full-width stacked buttons. primary fills one.

{
  "kind": "button-row",
  "buttons": [
    {
      "label": "Start today's plan",
      "action": {
        "startPlannedWorkout": true
      },
      "primary": true
    },
    {
      "label": "Start unplanned",
      "action": {
        "startEmptyWorkout": true
      }
    }
  ]
}

checklist

Tap-to-toggle rows. Each item carries its own action (usually { toggleHabit: id }); checked strikes the label, muted dims a row that isn’t relevant today, sublabel shows a streak or weekly count.

  • ✓

    Drink water

    6 days streak

  • Stretch

    2 / 3 this week

  • Cold shower

    Not due today

{
  "kind": "checklist",
  "items": [
    {
      "id": "a",
      "label": "Drink water",
      "checked": true,
      "sublabel": "6 days streak"
    },
    {
      "id": "b",
      "label": "Stretch",
      "checked": false,
      "sublabel": "2 / 3 this week"
    },
    {
      "id": "c",
      "label": "Cold shower",
      "checked": false,
      "muted": true,
      "sublabel": "Not due today"
    }
  ]
}

gauge

One value against a target — a hold-time goal, a range-of-motion reading, a milestone. style: "radial" (default) draws a 270° dial; "linear" draws a meter. value may exceed target (the host shows a “beaten” state). tone reuses the bar tones; sublabel overrides the auto "45 / 60 s" text.

80%
Couch stretch 48s / 60s hold
{
  "kind": "gauge",
  "label": "Couch stretch",
  "value": 48,
  "target": 60,
  "unit": "s",
  "sublabel": "48s / 60s hold"
}
Front split 12 / 20 cm to floor
{
  "kind": "gauge",
  "style": "linear",
  "label": "Front split",
  "value": 12,
  "target": 20,
  "unit": "cm to floor"
}

Need a primitive that isn’t here? The vocabulary is deliberately small — open an issue with the use case.