Skip to content

Primitives Tier 2: box/surface and prose/content across all five themes #54

Description

@fsecada01

Split out of #52 so Tier 1 could ship independently (acceptance criterion 7). The primitives layer landed in #53 with the five Tier 1 components — button, badge, heading, label, icon — across all five themes and both template sets. These two containers were scoped out of it deliberately.

What

Component Measured use in the reference repo What it is
box / surface 59 A plain bordered/elevated container. Distinct from card, which imposes a header/body/footer structure the caller cannot opt out of. Most uses are just "a thing with a border and some padding."
prose / content 61 Typographic reset for server-rendered or user-supplied HTML — the block where <h2>, <p>, <ul> inside a chunk of markup get sane styling without the caller writing a class per element.

Per component: base wrapper + 5 cotton theme partials + 5 jinja templates = 11 files. 22 for both.

What #53 already settled, and what it does not

Settled, and these should be reused rather than redesigned:

  • primitives.py is the vocabulary and the class map, and AXIS_KINDS declares whether an axis's value becomes a class, a tag, or an attribute. A container that takes only class-valued axes needs no new machinery.
  • Classes are spelled longhand in the templates because Tailwind's scanner reads source text. A bidirectional parity test binds primitives.py and the templates.
  • {% cf_ui_validate %} on the cotton wrapper, validate() in the jinja template.

Not settled, and this is the actual design work:

  • prose is the one primitive whose whole job is to wrap markup the caller supplies. Add a primitives layer: button, icon, badge, heading, label across all five themes #52's open question 4 called this out and feat(primitives): a primitives layer — button, badge, heading, label, icon (#52) #53 sidestepped it — Tier 1 primitives take slot content, so docs/escaping.md needed no new rule. prose does not get that luxury: if the content is a SafeString/Markup the caller built, the escaping contract has to be stated explicitly, and if it is user-supplied HTML the docs need to say plainly that cf-ui does not sanitize it and name what should.
  • daisy has no prose without the Tailwind typography plugin. prose is a @tailwindcss/typography class, not a daisyUI one. Either the daisy variant declares that plugin as a requirement (and themes.py / the docs say so), or it emits something else. This is the same shape of asymmetry that made grid questionable in Add a primitives layer: button, icon, badge, heading, label across all five themes #52 — decide it explicitly rather than discovering it in a consumer's build.
  • Does box take an axis at all? Bulma's box and Bootstrap's border rounded p-3 are not obviously variant-able. An elevation or padding axis may be right, or the component may legitimately have no axes and just be a themed container.

Acceptance criteria

  • box/surface and prose/content implemented as base + 5 cotton themes + 5 jinja themes each.
  • Names chosen and justified — one name per component, not the slashes above.
  • Any new axis added to primitives.py with an AXIS_KINDS entry, a closed vocabulary, and per-theme class maps; the existing parity and drift tests must cover it without modification.
  • The daisy prose decision documented in docs/primitives.md — whether it requires @tailwindcss/typography, and if so where that is declared.
  • The escaping contract for prose stated explicitly in docs/escaping.md, including that cf-ui does not sanitize caller-supplied HTML.
  • Docs page coverage matching the Tier 1 components.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationenhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions