Skip to content

Embed a Cooking Chart

One script and one tag. The recipe is drawn in the reader's browser, in the language it is written in, with no cookies and no tracking. It works on any website, static blog or CMS that allows HTML.

In one line

Load the script once and write the recipe in CCL inside <cooking-chart>. Indentation doesn't matter.

<script src="https://cookingchart.org/embed.js" defer></script>

<cooking-chart>
  recipe "Tomato toast"
  ingredients
    bread   1 slice
    tomato  1 pc
    oil     1 tbsp
  toast  = toast(bread) 3min unattended
  grated = grate(tomato) 2min
  dish   = assemble(toast, grated, oil) 1min
  serve dish
</cooking-chart>

Result

recipe "Tomato toast" ingredients bread 1 slice tomato 1 pc oil 1 tbsp toast = toast(bread) 3min unattended grated = grate(tomato) 2min dish = assemble(toast, grated, oil) 1min serve dish

From a .ccl file

If your recipes live in files, point to them with src. With controls readers can switch between as soon as possible and just in time.

Files on your own site always work; files on another domain need that server to allow CORS.

<cooking-chart src="/recipes/country_bread.ccl" controls></cooking-chart>

Result

Chart, work plan and method

Besides the chart, the element can show the recipe as text: the method, with sentences in the order you cook, and the work plan, step by step with its minutes. Pick which ones with view; if there are several, they show as tabs in that order.

With schema, the recipe is also published as schema.org structured data, which search engines use to show recipes.

<cooking-chart src="/recipes/chicken_tacos.ccl" view="method chart plan" schema></cooking-chart>

Result

In Markdown

If your blog is static (Hugo, Astro, Jekyll, Eleventy…), you don't need HTML: any code block marked as ccl turns into a chart on its own.

<!-- Once, in your blog template -->
<script src="https://cookingchart.org/embed.js" defer></script>

<!-- In any .md post -->
```ccl
recipe "Soft-boiled egg"
ingredients
  egg    1 pc
  water  500 ml
boiling_water = boil(water) 5min
soft_egg      = boil(egg, boiling_water) 6min no wait
serve soft_egg
```

Options

Attributes of <cooking-chart>. All of them are optional.

AttributeValuesWhat it does
srcURLLoads the recipe from a .ccl file instead of the tag's text.
modeasap · jitAs soon as possible or just in time. Defaults to the recipe's declared schedule.
langen · esForces the language of the chart labels. Defaults to the recipe's language.
controls—Shows the schedule switch.
variantsignatureThumbnail without text: the recipe's visual signature.
viewchart · method · plan · allWhat to show: chart, method or work plan. Several, separated by spaces, show as tabs. Default: chart.
schema—Publishes the recipe on the page as schema.org/Recipe JSON-LD.

With an iframe

For platforms that don't allow scripts but do allow iframes. The editor generates the code with the Embed button. The recipe travels in the URL hash (whatever comes after #), which browsers never send to the server.

<iframe src="https://cookingchart.org/e#ccl=cmVjaXBlICJ4Ii…"
        width="100%" height="420" style="border:0"
        loading="lazy" title="Lasagna bolognese"></iframe>

As an image

If a platform allows neither scripts nor iframes (social networks, some newsletter tools), use Download SVG in the editor. You lose interactivity, but the drawing is identical and scales without losing quality.

JavaScript

The script exposes window.CookingChart, and each <cooking-chart> has a small API.

<cooking-chart id="my-recipe"></cooking-chart>

<script>
  const el = document.getElementById('my-recipe');

  // Change the recipe: it is redrawn
  el.source = recipeText;

  // Know when it was drawn (and whether there were errors)
  el.addEventListener('cooking-chart:render', e => {
    const { recipe, diagnostics, ok } = e.detail;
  });

  // Validate without drawing
  const { ok, diagnostics } = CookingChart.parse(text, { locale: 'en' });
</script>
APIWhat it does
el.source = textChanges the element's recipe and redraws it.
cooking-chart:renderEvent after each render; detail has the recipe, the diagnostics and whether it is valid.
CookingChart.parse(text, options)Parses a recipe without drawing it. { locale: "en" } for English messages.
CookingChart.prepare(recipe, mode)Schedules a parsed recipe: times, slack, lanes.
CookingChart.method(scheduled)The method as data: ingredients, equipment and sentences per moment.
CookingChart.schema(scheduled)The schema.org/Recipe object, to publish it your own way.
CookingChart.upgrade(root)Converts ccl blocks added after the page loaded.
CookingChart.registerPack(pack)Registers a vocabulary pack (see below).

Styling

The chart lives inside a Shadow DOM: your site's styles don't break it and its styles don't touch your site. It takes the width of its container; to limit it, style the tag. The inner card is exposed as ::part(card).

Step colors are part of the standard and can't be changed, so any reader recognizes a Cooking Chart on any website.

cooking-chart { max-width: 960px; margin: 2rem auto; }

/* The inner card can be tweaked from outside */
cooking-chart::part(card) { border-radius: 0; border-color: #ddd; }

Your own vocabulary

If your recipes use verbs outside the base vocabulary (a kitchen-robot brand, pastry techniques…), register a pack and enable it in the recipe with use "name". For a one-off, a verb with the x- prefix and @kind: is enough.

<script src="https://cookingchart.org/embed.js"></script>
<script>
  CookingChart.registerPack({
    id: 'thermomix', version: '0.1',
    names: { es: 'thermomix', en: 'thermomix' },
    verbs: [
      // [id, kind, attention, Spanish forms, English forms]
      ['varoma', 'heat', 'passive', 'cocer_al_vapor', 'steam'],
      ['turbo',  'prep', 'active',  'turbo',          'turbo']
    ]
  });
</script>
<!-- and in the recipe:  use "thermomix" -->

Privacy

The script uses no cookies, doesn't track and doesn't send your recipes anywhere: all parsing and drawing happens in the reader's browser. It only downloads the drawing library (d3) from a public CDN if your page doesn't already have it.