apple-marketing-ui
by @chempa
Use when building a marketing site, product page, landing page, or launch surface that should look like apple.com - white/black tiles, tight display type, pill CTAs, atomic design.
Apple-aesthetic marketing UI
A design system for product and marketing surfaces in the spirit of apple.com. Derived from software-consultancy/ui-apple, a working Next.js starter that implements it.
Reach for this when the screen is meant to sell or announce something: a product page, a launch, a pricing page, a landing page. Do not reach for it for a dashboard or an internal tool - it depends on having very little to say per screen, and information density kills it. For that, use gitlab-admin-ui.
The aesthetic, in six rules
Restraint is the whole thing. If a decision is ambiguous, remove something.
- Three backgrounds. Exactly three.
#ffffff,#f5f5f7,#000000. Pick a
fourth and it stops looking like Apple.
- Two blues.
#0066ccfor link CTAs,#0071e3for pill buttons. Do not
introduce a third.
- Tight letter-spacing on big type.
-0.022emon display headlines is the
single biggest visual giveaway. Get this wrong and nothing else rescues it.
- Body text is
#1d1d1f, never pure black. - No shadows. No borders. The only border on a whole homepage is the
hairline above the footer.
- Roughly half of every tile is empty. Negative space is the product.
If you find yourself adding a third button variant, a fourth colour, or a new accent - stop. That urge is the aesthetic failing.
Copy: no em-dashes
Never use an em-dash (U+2014, the long dash) in any user-facing string: headlines, subheads, body, button labels, captions, alt text, metadata.
It is the loudest tell that copy was generated. Models reach for it constantly, real product copy almost never does, and once you notice it on a page you cannot stop noticing it. Apple's own site does not use it.
Rewrite the line; do not swap in a look-alike (a hyphen, or two hyphens) and call it fixed. Written below as [EM] because this file, like the copy it describes, does not contain one:
bad Built for speed [EM] and for you.
good Built for speed. And for you.
good Built for speed, and for you.
bad Three finishes [EM] silver, graphite, gold.
good Three finishes: silver, graphite, gold.
A full stop is almost always the better edit. Two short sentences read as confident; an em-dash reads as a sentence that could not decide where to end.
The same goes for en-dashes in prose. Keep them only in numeric ranges (10-20), where a hyphen is fine anyway.
Start here
Copy the token block first; every component below just spends these variables:
references/tokens.css -> your src/app/globals.css
Read references/tokens.css before writing a component. It is annotated, including why the font stack is ordered the way it is (Apple devices get real SF Pro for free; everyone else gets Inter, which was designed to fill exactly that gap).
Tiles, not pages
The foundational primitive is a full-bleed, single-subject, vertically stacked section. A page is a stack of tiles with alternating backgrounds.
<Tile tone="light">…</Tile>
<Tile tone="dark">…</Tile>
<Tile tone="white">…</Tile>
Never put two same-toned tiles next to each other - that is what turns a page back into a generic website. Tiles carry 120px of vertical padding routinely and min-h-[85vh] when they are heroes.
Content stays inside a 980px container. Images may break out full-bleed; text never does.
Five levels
This system has five layers, one more than a typical admin system, because the top level is content:
| Level | Lives in | What it is | Examples |
|---|---|---|---|
| Atoms | atoms/ | Smallest meaningful parts. Pure presentation. | Button, Input, Label, Eyebrow, Display, Toggle, Badge |
| Molecules | molecules/ | Atoms composed into the smallest functional unit. | HeadlineBlock, CTARow, FormField |
| Organisms | organisms/ | Self-contained page sections. | Tile, HeroSection, Nav, Footer, Card, PricingCard, SplitTile, FeatureRow, SpecSection, PromoBanner |
| Templates | templates/ | Page layouts with slots, no real content. | MarketingTemplate, GalleryTemplate, PricingTemplate, ProductDetailTemplate |
| Pages | pages/ | A template instantiated with real content. Not reusable. | HomePage, PricingPage, ProductDetailPage |
The rule that holds it together: an atom cannot import a molecule, a molecule cannot import an organism. Dependencies flow strictly downward.
The pages/ layer is what keeps the other four clean. Real copy, real image paths, and client-specific quirks all land there, so everything below stays reusable across projects.
See references/components.md for the CTA primitive, the Tile contract, and the conventions the components share.
Using it as a starter
This system is distributed as a repo you clone per project, not a package you install. references/starting.md has the full sequence - detaching from the starter's git history, what to keep versus replace, and the retitle checklist.
The short version: keep atoms/ through templates/ and globals.css - those are the design system. Replace pages/ and the showcase routes.
When you want a different aesthetic
Do not retune the tokens away from Apple. The components hard-code Apple's pill radii, chevron CTAs, and tile rhythm, so a recoloured globals.css produces something that is neither Apple nor coherent.
Fork into a sibling ui-<aesthetic> and rewrite the components instead. One design system per repo is the rule - gitlab-admin-ui is the same idea for dense technical tools.
Maintainability
A design system distributed by cloning has one dominant failure mode, and it is not visual.
The forks diverge, and fixes land in one of them. Twelve projects cloned from this starter are twelve copies of atoms/, and a focus-ring accessibility fix made in project seven is absent from the other eleven, silently, forever. Accept this consciously rather than discovering it:
- Fix upstream first, then pull forward. When a bug is in the system rather
than the project, land it in ui-apple and cherry-pick down. Fixing only the copy in front of you is how the starter becomes the least correct version of itself.
- Keep a note of the starter commit each project was cloned from. Without
it, nobody can tell what a project is missing, and the question is unanswerable after the first year.
- Reserve
pages/for divergence. Everything above it should still be
diffable against upstream. Once a project edits atoms/, it has left the system and every future fix is manual.
Tokens are the indirection that makes restyling cheap. A component spending var(--color-ink-primary) is one that a rebrand can move. A component with #1d1d1f in it is one that has to be found. That is the entire argument for the token file, and it is why a hex value appearing outside it is a real defect rather than an inconsistency.
Every variant you add is permanent. A third button style, a fourth background, a second CTA shape: each one is a thing every future page has to choose between, and choices are what the six rules exist to remove. The restraint at the top of this file is a maintainability constraint that happens to also be an aesthetic one.
See the maintainability skill for the general treatment of drift and deletion.
Stack
Next.js App Router, Tailwind v4 (@theme tokens), clsx + tailwind-merge as cn(). No component library, no icon set beyond a literal › chevron.
Source
git@gitlab.com:software-consultancy/ui-apple.git, whose sibling is ui-gitlab.