Put the recipe next to the coffee
Paste four lines into a product page or a blog post, and your readers get the dose, the water and every timed pour as a card they can brew from. No plugin, no account, nothing to host.
Where it earns its place
-
A roaster's product page
Sell the bag with the way you brew it. A shopper sees your dose, ratio and pours before they buy, and the first cup at home tastes the way you meant it to, not the way they guessed.
The Answer, as CoffeeJSON -
A blog post or a brew guide
Give readers a recipe they can follow, not retype. Open shows it full size, with a timer that walks through each pour when the recipe has timed pours. Download hands them the file, for any app that reads CoffeeJSON.
James Hoffmann Ultimate V60, as CoffeeJSON -
A shop that strips scripts
Some store builders remove scripts, so the card never draws. The link inside it still opens the whole recipe, and the same link prints as a QR for the bag: the generator makes a sheet of them.
Why four lines are enough
-
Nothing to keep running
The whole recipe rides inside the four lines on your page. Nothing is stored on a server, and there is no account to make or renew.
-
In your words and your colors
Name the buttons and captions in your page's language, show metric or imperial, and restyle the card with CSS. The attributes below say how.
-
Readable by search engines
Tick the box and the page carries the recipe as schema.org data, so a search engine reads the steps instead of guessing them from prose.
Attributes
| Attribute | What it does |
|---|---|
src | A URL that serves the document. Fetched, then checked like any decoded document. |
d | A payload, the same string a share link carries after ?d=. Wins over src. Padding is accepted, so a template filter that emits padded URL-safe Base64 produces a valid value. |
units | metric, imperial or as-authored (the default). |
lang | A BCP-47 tag for the digits, for example de for a decimal comma. |
viewer | A viewer's URL, absolute or a path on your site, http or https only. Adds an "Open" link to it with the payload as ?d=. Without it there is no such link, because the package picks no host for you. |
viewer-label | The text of that link, in your page's words and language. The default is "Open". The value is shown as text, never as markup. Without viewer it does nothing. |
labels | Captions in your page's words, as JSON: a PartialLabels object, merged over the English defaults the way the React cards' config.labels is, so you name only what changes. actions.download is the Download button. A value that is not a JSON object keeps the defaults; the element still renders and reports nothing, because the document is fine. Every label is shown as text, never as markup. |
jsonld | When present, the element adds the document's schema.org JSON-LD to the page's <head>, and removes it when the element goes. When absent, it adds nothing, because your page may already describe the same product. |
A page with script can set labels as an object on the
element's property instead. The element fires coffeejson-load
and coffeejson-error, and both bubble. Theme it with the
--cj-* custom properties and ::part(). The
package README has the rest.
Every card on this page is drawn by the script the snippet
loads, at version 1.2.0, from the npm CDN. This
site is demonstrating the element, not listing who uses it:
the showcase says what has shipped.