# Choice

> Pick one answer, or every answer that applies.

```json
{
  "id": "p1",
  "prompt": "On a checkout page, which action should be primary?",
  "hint": "What is the one thing this page exists to help people do?",
  "explanation": "Checkout exists to complete the purchase, so **Place order** is the primary action.",
  "type": "choice",
  "options": [
    {
      "id": "a",
      "text": "Place order"
    },
    {
      "id": "b",
      "text": "Continue shopping",
      "feedback": "Useful, but it pulls people away from finishing their purchase."
    },
    {
      "id": "c",
      "text": "Apply coupon",
      "feedback": "Only some people need it, so it shouldn't compete with the main action."
    }
  ],
  "correct": [
    "a"
  ],
  "multiple": false
}
```

The most common question brick. Two to five options, with one or more correct.

## When to use it

* Facts, rules, and predictions ("What does this log?").
* Numeric questions: v1 has no number input, so ask them as a choice whose wrong options come from real mistakes.
* Set `multiple: true` for "pick all that apply".
* Put a `visual` on the brick when the question is about something to look at, like a chart, a screen, or a diagram. It shows above the options.
* Give the options visuals when the answers themselves are something to look at: which layouts, charts, or components get it right.

## Fields

| Field      | Required | Description                                    |
| ---------- | -------- | ---------------------------------------------- |
| `options`  | yes      | 2–5 options, each with `text` or a `visual`    |
| `correct`  | yes      | Ids of the correct options                     |
| `multiple` | yes      | `true` to allow several picks, `false` for one |

Every wrong option needs `feedback` that explains the misconception.

## Visual options

When any option has a `visual`, the options show as cards in two columns, like [Compare](https://learn.ninja/docs/bricks/compare), each labelled "Option 1", "Option 2", and so on. A `text` on an option becomes a short caption under its visual.

* Give every option a visual, so the cards line up and none of them stands out by format alone.
* Give every option a short `text` caption too. Screen readers can't see inside a visual, so the caption is what they announce.
* Keep each visual small and focused on the one difference that matters. Each must be under 20 KB.
* HTML visuals are static HTML, CSS, and inline SVG, with the built-in UI kit and Tailwind utilities. No JavaScript, and nothing loaded from an external URL, so no linked images or photos.
* On a phone, the cards stack in one column.

## More examples

Pick all that apply:

```json
{
  "id": "p2",
  "prompt": "Which belong in a problem statement? Pick all that apply.",
  "hint": "Would it still be true if you picked a completely different solution?",
  "explanation": "A problem statement covers who is affected and why we believe it, independent of any solution.",
  "type": "choice",
  "options": [
    {
      "id": "a",
      "text": "Who is affected"
    },
    {
      "id": "b",
      "text": "Evidence, like data or quotes"
    },
    {
      "id": "c",
      "text": "The proposed screen design",
      "feedback": "That's a solution. It comes later, in design."
    },
    {
      "id": "d",
      "text": "The database to use",
      "feedback": "Implementation details don't belong in the problem."
    }
  ],
  "correct": [
    "a",
    "b"
  ],
  "multiple": true
}
```

Pick all that apply, with visual options:

```json
{
  "id": "p5",
  "prompt": "Which of these dialog footers follow the button hierarchy? Pick all that apply.",
  "explanation": "A good footer has one filled button for the main action and lighter styles for the rest. That works with two buttons or three.",
  "type": "choice",
  "options": [
    {
      "id": "a",
      "text": "Filled Save, outlined Preview, text Cancel",
      "visual": {
        "kind": "html",
        "html": "<div class='flex gap-2 flex-wrap'><button class='btn' data-size='sm'>Save</button><button class='btn' data-size='sm' data-variant='outline'>Preview</button><button class='btn' data-size='sm' data-variant='ghost'>Cancel</button></div>"
      }
    },
    {
      "id": "b",
      "text": "Filled Save, filled Cancel",
      "visual": {
        "kind": "html",
        "html": "<div class='flex gap-2 flex-wrap'><button class='btn' data-size='sm'>Save</button><button class='btn' data-size='sm'>Cancel</button></div>"
      },
      "feedback": "Cancel is filled too, so it competes with Save for attention."
    },
    {
      "id": "c",
      "text": "Filled Save, text Cancel",
      "visual": {
        "kind": "html",
        "html": "<div class='flex gap-2 flex-wrap'><button class='btn' data-size='sm'>Save</button><button class='btn' data-size='sm' data-variant='ghost'>Cancel</button></div>"
      }
    },
    {
      "id": "d",
      "text": "Text Save, filled Cancel",
      "visual": {
        "kind": "html",
        "html": "<div class='flex gap-2 flex-wrap'><button class='btn' data-size='sm' data-variant='ghost'>Save</button><button class='btn' data-size='sm'>Cancel</button></div>"
      },
      "feedback": "This flips the hierarchy: the main action is the weakest button, and Cancel gets all the weight."
    }
  ],
  "correct": [
    "a",
    "c"
  ],
  "multiple": true
}
```

With a visual (an inline SVG chart):

```json
{
  "id": "p5",
  "prompt": "Both accounts start with $1,000 and earn 7% a year. Which line is the one that compounds?",
  "visual": {
    "kind": "html",
    "html": "<svg viewBox='0 0 300 150' direction='ltr' class='w-full max-w-sm' font-size='10'><line x1='36' y1='132' x2='284' y2='132' class='stroke-border' /><line x1='36' y1='16' x2='36' y2='132' class='stroke-border' /><text x='30' y='19.0' text-anchor='end' class='fill-muted-foreground'>$8k</text><text x='30' y='77.0' text-anchor='end' class='fill-muted-foreground'>$4k</text><text x='30' y='135' text-anchor='end' class='fill-muted-foreground'>$0</text><text x='36' y='146' text-anchor='middle' class='fill-muted-foreground'>0</text><text x='280.0' y='146' text-anchor='middle' class='fill-muted-foreground'>30 yrs</text><polyline points='36.0,117.5 280.0,87.0' fill='none' stroke-width='2.5' class='stroke-muted-foreground' /><polyline points='36.0,117.5 52.3,115.4 68.5,113.0 84.8,110.2 101.1,107.1 117.3,103.5 133.6,99.3 149.9,94.6 166.1,89.2 182.4,83.0 198.7,75.9 214.9,67.8 231.2,58.5 247.5,47.8 263.7,35.6 280.0,21.6' fill='none' stroke-width='2.5' stroke-linejoin='round' class='stroke-primary' /><text x='286' y='25' font-weight='600' class='fill-foreground'>A</text><text x='286' y='90' font-weight='600' class='fill-foreground'>B</text></svg>"
  },
  "explanation": "Compound interest earns interest on past interest, so it adds more each year and the line curves up. Simple interest adds the same $70 every year: a straight line.",
  "type": "choice",
  "options": [
    {
      "id": "a",
      "text": "Line A: it adds more each year"
    },
    {
      "id": "b",
      "text": "Line B: it grows steadily",
      "feedback": "Steady growth means the same amount every year. That's simple interest, paid on the first $1,000 only."
    },
    {
      "id": "c",
      "text": "Neither yet: compounding only kicks in after 20 years",
      "feedback": "It starts in year one; it's just small at first. By year 10, A is already ahead, $1,967 to $1,700."
    }
  ],
  "correct": [
    "a"
  ],
  "multiple": false
}
```

With code:

```json
{
  "id": "p2",
  "prompt": "What does this log?",
  "visual": {
    "kind": "code",
    "code": "const names = ['ada', 'linus'];\nconst upper = names.map(n => n.toUpperCase());\nconsole.log(names);",
    "language": "javascript"
  },
  "hint": "Which variable is being logged?",
  "explanation": "map returns a new array, so `names` is unchanged.",
  "type": "choice",
  "options": [
    {
      "id": "a",
      "text": "`['ada', 'linus']`"
    },
    {
      "id": "b",
      "text": "`['ADA', 'LINUS']`",
      "feedback": "That's `upper`. map leaves the original array alone."
    },
    {
      "id": "c",
      "text": "`undefined`",
      "feedback": "`names` is still the original array."
    }
  ],
  "correct": [
    "a"
  ],
  "multiple": false
}
```
