One yes-or-no fact, stored true/false — three affordances, and the three-state smell that outgrows them.
One yes-or-no fact: featured, sold out, members-only, show-the-map.
Stored as a boolean — that word is the data type's, one row down — and
titled Toggle by deliberate choice of the friendliest widget's name over
the contract's. The section's rule is that families take the contract's
name (which is why select went back to naming just a method), and this
page is the named exception: every trade calls the two-state field
something different, no plain word won outright, and the switch is what
an author actually sees.
true or false — never "yes", never 1. The write boundary refuses
anything that is not a boolean, so the template's if never has to ask
what kind of truthy arrived. All three methods below store exactly this;
none of them changes what a template reads.
| Method | The affordance | Reach for it when |
|---|---|---|
| Switch | a setting that takes effect | enabling a feature, a mode, a display option |
| Checkbox | a single opt-in inside a form | agreeing, including, marking one item |
| Radio | two named options | both states deserve a word, or neither is the default |
A method may name the two states for the author — Yes/No, True/False,
Live/Draft on a radio pair — and the stored value stays
true/false underneath. The test for whether that is honest: both
labels must be answers to one question. Live/Draft passes ("is it
published?"). Blue/Green fails — those are two things, not the two
answers to anything; storing one of them as true is an arbitrary
convention the next template author has to be told, and the day a third
colour arrives a boolean has nowhere to put it. Two named things are an
options field with two choices; the third choice then
costs one line, not a migration.
<% if (cms.asset.content.featured) { %>
<span class="badge">Featured</span>
<% } %>
{ "content": { "featured": true } }