Skip to content

Storefront design

Bloom and Noir were redesigned on 4 October 2026. The owner said the first versions looked generated, and they did: they used the combinations most templates use. This page records the rules the themes now follow, so later themes and changes keep to them. The themes themselves are described in Storefront runtime and themes.

The redesign followed a review of real florist and boutique shops, read from their live pages:

  • FLOWERBX: one variety per product, stem-length filters.
  • McQueens: one backdrop for every bouquet.
  • Désirée (Paris): a consistent photo frame and plain statements of limits.
  • Worm: an oversized wordmark and a manifesto line.
  • Aesop: a composition line under each product name.
  • Toast: story titles instead of “New arrivals”.
  • Kvitna (Lviv): a rail of what is in stock now, as the local baseline.

Tells to avoid, and what the themes do instead

Section titled “Tells to avoid, and what the themes do instead”
Template tell Bloom and Noir
Centred serif title in a rounded tinted box with one button A full-bleed photo with the title at the bottom left and a text link. Without a photo, a large type-only title beside today’s price list of stems
Pill category chips A typographic index: large category names with counts; occasions as rows on hairlines
Uniform rounded cards with shadows No card at all: photo, name, composition line, price. Square corners by default
A sage-green accent everywhere Ink carries every action. The shop’s accent marks only stock notes, active filters and focus
“New arrivals / Shop by category” Numbered sections on a hairline (01 — Вибір флориста) with specific default titles; shops rename them
Icon badges and icon trios Text: “Кошик (2)”, “UA / EN”. One plain line of facts from the shop’s own delivery note
Grey boxes with initials for missing photos A label card: a paper tone kept per product, its catalogue number, the name in the display face and its flowers
Equal spacing everywhere Tight inside a group, very large between sections
Bloom Noir
Display Piazzolla (optical sizes) Prata
Text Commissioner Sofia Sans, with Sofia Sans Extra Condensed for labels
Ground and ink Paper #FBF9F4, ink #1D1C19, hairline #DAD5CA Near-black #121110, bone #EDE8DF, rule #2E2B27
Default accent Oxblood #7A2E2A Brass #C2A06A

Fonts:

  • Every face supports Cyrillic and is installed from Fontsource, so it is served from the storefront itself.
  • Avoid faces without Cyrillic, such as Fraunces, Instrument Serif, DM Sans and Space Grotesk.
  • Avoid the overused pairs: Cormorant, Playfair, Lora, Montserrat.

Arrows and chevrons are drawn as SVG in the text colour and sized in em, never typed as glyphs such as ▾. Commissioner has no ▾, so the browser drew a tiny, misaligned fallback in the menus (fixed 4 October 2026).

Prices use tabular figures and the currency sign ₴, which the SDK pins so that Node and every browser print the same.

  • Home
    • The announcement bar shows the shop’s delivery note.
    • A hero, then numbered sections with no headings over empty data.
    • Today’s stems appear as a price list with dotted leaders.
    • The about text sets its first paragraph large.
    • The footer ends with the shop’s name set across the full width.
  • Catalogue
    • Category tabs, occasion and order menus, an in-stock toggle and search.
    • Every filter is a link, built from plain <details> menus, so it works without scripts under the strict CSP.
  • Bouquet
    • Photos stacked on desktop, or a swipeable row with “1 / 3” counters on phones.
    • A sticky column with packaging and quantity, and a button that shows the exact total.
    • The composition is an always-visible table with colour dots.
    • The occasions are links within a sentence.
  • Builder: a list of stems beside an order slip with a colour bar sized by stem count. On phones the total and the action stay at the bottom.
  • Cart: lines on hairlines, then a summary with the total and a “Checkout” button when the shop takes orders online, else the shop’s contacts.
  • Checkout (/checkout, ADR-014)
    • Bloom sets it as a printed order slip: numbered sections (how you receive it, when, your contacts, card and notes, payment) beside a sticky price list with dotted leaders. Noir uses one narrow column with the total last.
    • Choices are ruled boxes whose radio is the box itself; dates are one scrolling row; the three windows carry the same names as the staff form (Morning, Afternoon, Evening).
    • Every amount comes from the server’s quote. The button says “Send the request”, and the note under the total says the shop confirms first and nothing is paid now.
    • A changed or expired quote shows the new total and the button becomes “Confirm the new total”. The form keeps nothing in the browser.
    • The form logic is the SDK’s useCheckout; each theme only renders it.
  • Status page (/orders/{token}): the status as the heading, five steps (received, confirmed, being arranged, ready, delivered or collected), the price list, when and where, payment, and the shop’s contacts. Never cached or indexed.
  • Side cart, on by default; a shop can switch it off with the theme setting Side cart.
    • “Кошик (n)” opens a drawer from the right, and every add opens it, so the visitor sees the line land.
    • The drawer offers the full cart page or “continue shopping”.
    • It is a native modal <dialog>: focus stays inside, Escape and a click on the dimmed page close it, and the page behind does not scroll.
    • The header link stays a real link to the cart page, so it works before scripts load and with modifier-clicks.
    • Our own controls close the drawer directly instead of waiting for the dialog’s asynchronous close event. That event did not arrive in a tab without focus, which left the page scroll-locked.

Revised on 4 October 2026 from a review of Baymard Institute and Nielsen Norman Group research, WCAG 2.2 and the WAI-ARIA Authoring Practices, and the live headers of FLOWERBX, Bloom & Wild, Grace & Thorn, McQueens and Kvitna.

Desktop

  • Utility line (scrolls away): the shop’s delivery note, today’s hours and UA / EN.
  • Main row (68px, opaque, sticky):
    • The shop’s name on the left. On the right: a call link (handset icon and the number, tel:), “Пошук” and “Кошик (n)”.
    • Categories are top-level links: up to three, plus “Усі букети”. With more, they fold into one “Букети” group.
    • A “Привід” panel opens on click, never on hover alone. It lists occasions with counts and “Усі приводи” first.
    • Then “Зібрати букет” and “Контакти”.
  • Panels follow the WAI-ARIA disclosure pattern (a button with aria-expanded, not role="menu"). Escape returns focus to the button, and a click or focus outside closes them. The current page carries aria-current and an underline.

Phones

  • Header (56px): a text “Меню” button, the shop’s name, a 44px handset icon that calls the shop (labelled “Подзвонити +380…” for screen readers), and “Кошик (n)”. It slides away while scrolling down and returns on any scroll up. Only a transform changes, so nothing shifts.
  • The menu is a modal drawer from the left. In order:
    1. Search.
    2. Categories with counts and “Усі букети”.
    3. An occasions accordion.
    4. The builder.
    5. “Зв’язатися”: call and messengers, today’s hours, the delivery note.
    6. About, contacts and language, as full names.
  • Targets are at least 44–48px.
  • Not used: a bottom tab bar and floating messenger widgets. The phone is the one icon in the header, because a handset needs no label and calling is how most orders arrive until checkout opens.

Wayfinding everywhere

  • A “Перейти до вмісту” skip link, and scroll-padding-top so anchors and focused fields clear the sticky header.
  • Phone product pages open with “← Категорія”. Desktop product pages show “Головна / Категорія / Назва”, with the current page last and not a link.
  • A search or filter that finds nothing offers occasions and popular bouquets instead of a dead end.
  • Footer: contacts (call, messengers, email, address), opening hours, every category and the builder, every occasion, language.

Measured at 390×844 before and after the navigation and layout pass:

Before After
Header 100px (two rows) 57px
Home: first bouquet starts at 870px (below the fold) 683px, with the CTA (the call link is in the header)
Catalogue: first bouquet starts at 533px (four rows of filters) 289px
Bouquet: name and price 600px and lower about 650–690px, within the first screen

What changed:

  • Spacing. Sections sit clamp(3.25rem, 1.75rem + 5vw, 8.5rem) apart, instead of a fixed 7rem on phones. Section heads are tighter.
  • Text sizes. Display sizes use clamp() with a rem base, so text zoom still works.
  • Hero on phones: min(58svh, 30rem) high, with one action. The call link moved from the hero to the header, where it is on every page.
  • Lists. Bouquet lists are two-column grids, not rails, and every home list ends with “Усі букети (N)”.
  • Home order. The default order puts bouquets before the indexes, and contacts before the price list and the about text. On phones, the about text folds after its first paragraph.
  • Bouquet page:
    • The gallery is capped at min(62svh, 30rem) and the next photo peeks in.
    • The delivery note sits under the price, then “Або замовте: Подзвонити · Написати в Telegram”.
    • A bottom bar with the total and the action appears only once the inline button scrolls away, and the page keeps room for it.
    • Related bouquets come from the same category.
  • Catalogue on phones. Search lives in the menu; an active search shows as a removable chip. The filters take two short rows.
  • Contacts section. It opens with call and messenger buttons.

The demo shops use 20 free-licence photos (Unsplash and Pexels licences, listed in resources/demo/CREDITS.md) and a Ukrainian catalogue at real prices. This lets the design be judged on realistic content. Real shops upload their own photos; one consistent backdrop and framing does more for a shop than any theme.