Content Markup

Table of Contents

Content types


Maths formulas

Images and multimedia

Info and hint boxes

Blockly - inline syntax highlighting

Code - Syntax highlighting, examples, workspaces, files, encryption and languages

Custom Tags

Content Types

Module slide content and problem description content can be authored using one of two different markup notations: Markdown or raw HTML. Both markup approaches are fully supported. Any new material being authored on Grok should be written in Markdown as it's easier to use than the older-style raw HTML markup.

Using Markdown

Grok markdown is derived from CommonMark but implements extra functionality specific to Grok. To indicate that the content is in Markdown instead of raw HTML, the content field should start with the string #markdown.

Because it's much easier to write in markdown, there is a new "Convert to Markdown" button in the interface. If you've been writing in HTML before you should try out converting to markdown. However be aware that there are some edge cases it cannot handle, and you may lose information.

When using Markdown, you can also use arbitary HTML at any point in time, making the use of Markdown a superset of the functionality of the raw HTML markup. An example of when you might want to use this is to add a  textual alignment class to a paragraph of text.

The following content fields can be written in Markdown:

  • For modules, slide content.
  • For problems, the problem definition, solution notes, and teacher notes.

Using HTML

All content fields can be written using raw HTML, but the documentation here is provided mostly for when you need to use HTML because the styling or content you're authoring cannot be expressed in Markdown. Some examples include, blocks of content, blockly, interactive slides or complicated inline editors.


Component Markdown HTML
Paragraph A single blank line separates paragraphs.
A paragraph. 
With some text. 

Another paragraph. 
With some more text.
Enclosing  <p> tags:
  A paragraph.
  With some text.
  Another paragraph. 
  With some more text. 
Bold Enclosing double asterisks:
This is **bold text**.
Enclosing  <strong> tags:
This is <strong>bold text</strong>.
Italics Enclosing single asterisks:
This is *italic text*.
Enclosing  <em> tags:
This is <em>italic text</em>.
Hyperlinks Markup of the form  [hyperlink text](url):
[Here]( is a link to the data.
The  <a> tag, with the href attribute set to the desired URL, and the _target attribute set to _blank:
<a href="" target="_blank">Here</a> is a link to the data.
Unordered lists Asterisk-prefixed lines of text, after a blank line:
Lets start dot points:

* Here is a dot point
* Here is another dot point 
* And another one
An enclosing  <ul> tag, with each list item enclosed in a <li> tag.
  <li>Here is a dot point</li>
  <li>Here is another dot point</li> 
  <li>And another one</li> 
Ordered lists Number-prefixed lines of text.
Lets start number points:

1. Here is a numbered point 
2. Here is another point 
3. And another one
An enclosing  <ol> tag, with each list item enclosed in a <li> tag.
  <li>Here is a dot point</li> 
  <li>Here is another dot point</li> 
  <li>And another one</li> 

Maths Formulas

Grok uses MathJax to support rendering LaTeX maths equations in module and problem content. Inline maths should be enclosed in double dollar signs ( $$...$$) and block maths should be enclosed in triple dollar signs ( $$$...$$$). For example:

Note: We're having issues with the following example sometimes not showing $ as double or triple dollar due to a bug in our documentation software. We're looking in to this.

In mathematics, the factorial of a non-negative integer $n$, denoted by $n!$,
is the product of all positive integers less than or equal to n. For example:
$5! = 5 \times 4 \times 3 \times 2 \times 1 = 120$
We can write the formula for $n!$ as:
n! = \prod_{k=1}^n k = 1 \times 2 \times \ldots \times (n - 1) \times n
with the special case of $0! = 1$.

Images and Multimedia

Images, video and audio used in Grok modules and problems must be uploaded as assets. When linking assets make sure you use the uploaded asset URL, not the location of the original file. Additionally, only creative commons content, or content you have explicitly checked rights for should be used. An attribution to the original location of the uploaded multimedia should be included in the caption of the figure.

Video and audio support across browsers is complex; there's a  good article here. Our recommendation for best browser support is to use MP4 for video and MP3 for audio. To convert to MP4 this is a good guide.

The markup for including an image, video or audio file is as follows:


Image, video and audio can be added using Markdown syntax   ![alt text](url "caption text"). This can be used either inline in paragraph text or standalone. When standalone they will be centered and the caption displayed underneath. If the caption text is not specified, it will default to the alt text.

![Image from *Wikipedia*](

Note that the alt text can itself be Markdown.

Video or audio URLs will be automatically given playback controls based on the file extension.

Image HTML

The following fragment, accessible via ^/⌘-7 in the full-screen editor.

  <img alt="Image alt text" src="">
  <figcaption>Image from <a href="https://..." target="_blank">Wikipedia</a>.</figcaption>

Video HTML

  <video src="" controls></video>
  <figcaption>Video from <a href="https://..." target="_blank">Wikipedia</a>.</figcaption>

Audio HTML

  <audio src="" controls></audio>
  <figcaption>Audio from <a href="https://..." target="_blank">Wikipedia</a>.</figcaption>

Info and Hint Boxes

The markup for including an info box is as follows:


The Grok Markdown representation uses the blockquote functionality of CommonMark. Any block quote that starts with a level-2 heading will become a hint box.

> ## Hint 
> Hint content goes in here.
> ## type:design;Design Tip 
> The design type turns it into a design tip (blue box with a pencil icon).


The following fragment, accessible via ^/⌘-6 in the full-screen editor.

  <p>Hint content goes in here. Add the optional class "design" to turn it into a design tip.</p>

Blockly — Inline syntax highlighting

Inline Blockly syntax highlighting can be achieved in HTML only. The custom HTML  <bk> element is used for inline Blockly blocks. These <bk> elements need the appropriate CSS class to specify which kind of block (colour) they appear as. These blocks can also be nested.

The following classes are available:

CSS Use Example
control Control structures
<bk class="control">for each</bk>

for each

func User-defined functions
<bk class="func">do something</bk>

do something

inner Completed input placeholders
<bk class="lib">pen <bk class="inner">up</bk></bk>

pen up

io IO blocks
<bk class="io">print</bk>


lib Library functions (variant 1)
<bk class="lib">do something</bk>

do something

lib2 Library functions (variant 2)
<bk class="lib2">do something</bk>

do something

list List operations
<bk class="list">sort <bk class="var"><bk class="inner">names</bk></bk>

sort names

list lit List literals
<bk class="list lit">
  <bk class="math">
    <bk class="inner">42</bk>, <bk class="math"><bk class="inner">16</bk

42 , 16

logic Logical tests
<bk class="logic">
  <bk class="math">
    <bk class="inner">42</bk> &le; <bk class="math"><bk class="inner">16</bk>

42 16

math Maths and numbers
<bk class="math"><bk class="inner">42</bk></bk>


script JavaScript operations
<bk class="script">
  <bk class="inner empty"></bk> + <bk class="inner empty"></bk>

element matching selector h2

str String operations
<bk class="str">element matching selector <bk class="str lit"><bk class="inner">h2</bk></bk></bk>


str lit String literals
<bk class="str lit"><bk class="inner">Hello!</bk></bk>


var Variables
<bk class="var"><bk class="inner">name</bk></bk>


Code — Inline syntax highlighting

Inline syntax highlighting can be achieved in the following ways:


Single backticks are used to produce inline syntax highlighting. By themselves, the content inside the backticks is assumed to be the default language of the module or problem. This can be overwritten by specifying the lang option directly after the first backtick, followed by a semicolon. 

The code `print('Hello')` will output `lang:out;Hello` to the screen.


<code> tag with a  data-lang attribute set to a lang. All of these tags must be annotated with a  data-lang attribute. In the full-screen editor, this is accessible via ^/⌘-1.

<code>The code <code data-lang="py3">print('Hello')</code> will output <code data-lang="out">Hello</code> to the screen.

Code — Workspaces

To show a larger code snippet or a runnable example, you can embed files into your content. Most files are embedded using code blocks, which are described in detail below,

These files are grouped together into workspaces, which allows you to have examples that involve multiple files. Each workspace has an ID which must be unique to the entire course. When using Markdown, these IDs will be generated for you, with HTML you must specify them manually.

In addition to code files (e.g., data.txt, etc), you can embed other parts of the workspace, such as the terminal output, generated animations (e.g. logo), live web preview, or simulated devices output (e.g. micro:bit).

In most cases, the first code block will be the default file for the workspace (e.g. for a slide in a module with the default language set to Python, the file will be so it will not need to have a file name specified manually.

Code — Files

Code blocks come in many different varieties and have a number of configuration options. The general template for a code block is as follows:


Triple backtick-enclosed non-HTML-escaped content. After the opening triple backtick, semicolon-separated key and optional value configuration options can be supplied:

for i in range(10):  
  if i < 5:


<code> enclosed in a  <pre>, with all configuration options other than the lang defined on the  <pre>. Since this is HTML, the code inside the  <code> tag needs to be HTML escaped:

<pre data-name1="value1" ...>
  <code data-lang="...">
for i in range(10):
  if i < 5:

Most code blocks require very few options other than the workspace ID. In HTML, all options are set on the <pre> element unless otherwise specified.

Action Markdown option HTML attribute
Set the workspace ID eg:last|<id> (Note: defaults to generated ID. Use last to use the ID of the previous block, and <id> to manually set an ID.) data-eg-id="<id>"
Make it a main file editor Do nothing. class="js-editor"
Make it non-main file editor path:<path> class="js-file-editor" data-path="<path>"
Set the language (see below) lang:<lang>
(Note: defaults to problem/module language)
(Note: must be set on the  <code> element.)
Set no workspace ID eg:none Defaults to none.
Hide the run button norun data-runnable="false"
Make it readonly readonly data-readonly="true"
Hide it (used to add a hidden file to the workspace) hidden style="display: none"
Encrypt the contents (see below) encrypted Not available.
Mark as exportable exportable data-exportable="true"
(Note: must be set on the  <code> element.)
Set the content URL for a URL file content-url:<url> data-content-url="<url>"

In addition to code files, other workspace features can be embedded using a similar syntax. Most of these can optionally have pre-loaded content (e.g. the terminal or animations). They all require the workspace ID to be set (for Markdown, this will usually mean  eg:last;, for HTML you will have to set it manually).

Feature Markdown option HTML attribute
Interactive terminal output (a “terminal”) terminal class="js-terminal"
Hardware device output/animation device-(output|animation) class="js-device-(output|animation)"
Above, but with looping device-animation:loop class="js-device-animation" data-loop="1"
Python Turtle animation/final logo-(animation|final) class="js-logo-(animation|final)"
Image Ordering picture image-ordering class="js-image-ordering"
Above, but animated image-ordering:animate class="js-image-ordering" data-animate="1"
Live web preview live-web-preview class="js-live-web-preview"
Turtle Initialisation File;exportable; class="js-file-editor" data-path="" data-exportable="true"

Some additional options are described below:

Action Markdown option HTML attribute
Height height:<height> data-height="<height>"
Zoom (Live web preview only) zoom:<zoom> data-zoom="<zoom>"
Set the workspace language (see below) Not available data-lang="<lang>"
(Note: must be set on the  <code> element.)

Code — Encrypted Examples

Sometimes it's useful to provide a code snippet that demonstrates the expected behaviour of a problem. This would require putting the solution to the problem in the slide, which is a problem if the student can see the code. Encrypted blocks prevent the code from being available in the browser.

The encrypted attribute will also implicitly hide the editor, so you will need to manually create an output element (e.g.device-output or terminal).

Click run! 
name = input('Name? ')
print('Hello, ' + name + '!')
Name? @@@Grok Hello, Grok!

Code — Languages

For the purposes of syntax highlighting, there are a number of different "languages" that can be used on any code snippet, executable or not. When using Markdown, files will default to the problem or module language, so setting these explicitly is usually not necessary.

The following langs are available for use:

  • arduino: Arduino code
  • atom: HTML atom highlighted content
  • attr: HTML attr highlighted content
  • bash: Bash code
  • bashshell: Bash interactive shell (with prompt)
  • blockly: Blockly XML code (see below)
  • c: C code
  • cc: C++ code
  • css: CSS code
  • err: Error-highlighted content
  • fits: Astronomy FITS files
  • haskell: Haskell code
  • html: HTML code
  • image_ordering: Monsters (image ordering) code
  • in: Input-highlighted content
  • java: Java code
  • jpeg: JPEG files
  • js: JavaScript code
  • json: JSON files
  • logo: Python Turtle code
  • meta: HTML meta highlighted content
  • microbit_micropython: micro:bit MicroPython code
  • octave: MATLAB/Octave code
  • out: Output-highlighted content
  • png: PNG files
  • prolog: Prolog code (SWI)
  • psql: PostgreSQL code
  • psqlshell: PostgreSQL psql shell (with prompt)
  • py3: Python 3 code
  • py3idle: Python 3 shell (with prompt)
  • py3_large: Python 3 code with much larger resource limits. Mainly used for scientific computing questions
  • py3_psql: Python 3 + PostgreSQL code, where Python can use the psycopg2 library
  • py3_uptick: Python 3 code with larger resource limits and the CMCRC uptick library
  • r: R code
  • sqlite: SQLite code
  • str: String-highlighted content
  • svg: SVG code
  • tag: HTML tag highlighted content
  • txt: Regular text file
  • xml: XML code

In some rare situations, it may be necessary to set the workspace language explicitly. For example, if the only file in the workspace is Blockly, and not generating Python. For Markdown, the workspace language will default to the module/problem language. For HTML you will have to set it explicitly using  data-workspace-lang="" on the <code> element.

Custom Tags

We define some custom tags for use in authoring:

Tag Usage Notes
grok-condition <grok-condition [options]></grok-condition> Interactive slides.
grok-if <grok-if [show|hide|flash]> ... </grok-if> Interactive slides. Wraps grok-condition elements.
grok-step <grok-step> ... </grok-step> Interactive slides. Auto-numbered step format.
grok-breakout <grok-breakout> ... </grok-breakout> Full width slide content that breaks out of the 680px main column. All content inside the tags displays at a max of 1200px, and shrinks to fit any size screen.
grok-microbit-leds <grok-microbit-leds values="0, 9, 0, ..."> </grok-microbit-leds> DIsplay the standard array of 25 microbit leds (without running the simulator). Most often used in image tables. See also Writing micro:bit content.