Help center

Building content right: Markdown, HTML and animation

What works in the two formats of the editor, what the screen removes and how long animated content may run. With examples to copy.

Content with the Document template is text that you write in the editor as Markdown or as HTML. You choose between the two in the Format field. Markdown is enough for most texts, HTML is what you need for your own design and for motion.

This guide shows what works in both formats, what the screen removes and how long animated content may run. Every example can be copied and pasted into the editor; the preview next to it shows right away how it looks on the screen.

Markdown

Markdown is plain text with a few characters for the layout.

Format text

  • # Title, ## Subtitle for headings
  • **bold**, *italic*
  • Start a line with - for a bullet list, 1. for a numbered one
  • New line: just press Enter
  • --- on its own line draws a divider
  • [Text](https://…) for a link
  • Insert an image: the Insert image button above the text field. To align it, put "center" or "right" after the image URL, e.g. ![Title](url "center") (left otherwise)

Icon shortcodes

A shortcode turns into a coloured icon button, the second form is also animated:

  • :phone: / :phone-ring: phone, rings
  • :link: / :link-pulse: link, pulses
  • :mail: / :mail-shake: letter, shakes
  • :calendar: / :calendar-flip: calendar, flips
  • :location: / :location-bounce: location, bounces

A time like 10:30 stays unchanged.

HTML inside Markdown

Markdown may contain raw HTML, such as a <div> or a <style> with an animation. The same rules apply as in the HTML format, including those on length. What the screen removes is described in the next section.

Example in Markdown
# Water outage

On **Tuesday** the water is off from 8 to 11 am.

- Please fill a jug beforehand.
- The property management answers questions :phone:

---

Thank you for your understanding.

HTML

In the HTML format you write an HTML fragment, without <html>, <head> and <body>.

Allowed formatting

Common tags work: <h1> to <h3>, <p>, <strong>, <em>, <ul> / <ol> / <li>, <a href="…">, <br>, <mark>. For layout you have <div> and <span> with class and style, and your own CSS goes into a <style>.

Images

Images from the media library only, meaning addresses under /cdn/assets/…. In the media library the Copy URL button copies the address of an image. The screen removes an <img> with a foreign address entirely, as it does an <image> in an SVG graphic.

Addresses in CSS

CSS may only load what comes from the media library as well. This applies to url() in any property, to image-set() and to @import, in a style attribute as in a <style> block. In addition, you may embed images and fonts directly as data:, such as a font with src: url(data:font/woff2;base64,…) in @font-face. If the CSS contains any other address, the content cannot be saved, and the editor points this out beforehand in a note.

What is removed

Before showing content, the screen removes:

  • every <script>
  • <iframe>, <object> and <embed>
  • event handlers such as onclick or onload
  • links with javascript:
  • images, videos and sounds from foreign addresses (<img>, <video>, <audio>, <source>)
  • CSS with a foreign address: in a style attribute the whole attribute is dropped, in a <style> block the affected rule
  • in SVG graphics every reference to another file, such as fill="url(https://…)" or <use href="https://…">
  • anything that is not on the lists in the next section, such as <input>, <form> or the attribute background on a table

If your content contains any of this, the editor shows a note below the text field. Such content cannot be saved, and the rejection names the spot. The one exception is an image in Markdown notation with a foreign address: it is saved, but does not appear on the screen.

Icon badges

Shortcodes like :phone: work in Markdown mode only. In HTML you write the badge directly as a <span> with two classes, and a third class sets it in motion:

  • Phone: q-ico q-ico-tel, ringing with q-anim-ring
  • Link: q-ico q-ico-link, pulsing with q-anim-pulse
  • Letter: q-ico q-ico-mail, shaking with q-anim-shake
  • Calendar: q-ico q-ico-cal, flipping with q-anim-flip
  • Location: q-ico q-ico-pin, bouncing with q-anim-bounce

For example <span class="q-ico q-ico-tel q-anim-ring">☎</span>.

Example in HTML
<div>
  <h2>Laundry room</h2>
  <p>The new schedule applies from <strong>1 November</strong>.</p>
  <ul>
    <li>Monday to Friday, 7 am to 9 pm</li>
    <li>Saturday, 8 am to 6 pm</li>
  </ul>
  <p><mark>The laundry room stays closed on Sundays.</mark></p>
  <p><span class="q-ico q-ico-tel">☎</span> The property management answers questions.</p>
</div>

Allowed elements and attributes

The screen only shows elements and attributes that are on the lists below. It removes everything else before display, and the editor points this out to you beforehand with a note. For an element such as <font> or <center> only the element is dropped, the text inside it stays. The lists are the same ones the screen uses for cleaning up.

SVG graphics are allowed, including gradients, masks and shadows. A reference may only point within the content, such as fill="url(#gradient)" or <use href="#dot">. The screen removes references to other files and images from foreign addresses.

HTML elements

<h1><h2><h3><h4><h5><h6><p><br><hr><div><span><section><article><figure><figcaption><strong><b><em><i><u><s><mark><small><sub><sup><code><pre><blockquote><ul><ol><li><table><caption><thead><tbody><tfoot><tr><th><td><a><img><video><audio><source><track><style>

SVG elements

<svg><g><defs><symbol><use><title><desc><path><rect><circle><ellipse><line><polyline><polygon><text><tspan><clipPath><mask><pattern><marker><linearGradient><radialGradient><stop><image><filter><feDropShadow><feGaussianBlur><feOffset><feFlood><feComposite><feMerge><feMergeNode><feBlend><feColorMatrix>

Attributes on every element

classidtitlelangdirrolestylearia-…data-…

Additional attributes of individual HTML elements

  • <a>: hrefxlink:hreftargetrel
  • <img>: srcaltwidthheight
  • <video>: srcposterwidthheightcontrolsautoplayloopmutedplaysinlinepreload
  • <audio>: srccontrolsautoplayloopmutedpreload
  • <source>: srctype
  • <track>: srckindsrclanglabeldefault
  • <ol>: startreversedtype
  • <li>: value
  • <th>: colspanrowspanscope
  • <td>: colspanrowspan

Attributes on every SVG element

xmlnsxmlns:xlinkviewBoxpreserveAspectRatiotransformxywidthheightcxcyrrxryx1y1x2y2fxfydxdydpointspathLengthfillfill-opacityfill-rulestrokestroke-widthstroke-linecapstroke-linejoinstroke-dasharraystroke-dashoffsetstroke-miterlimitstroke-opacityopacitycolordisplayvisibilityvector-effectpaint-orderfont-familyfont-sizefont-weightfont-styletext-anchorletter-spacingword-spacingtext-decorationdominant-baselinealignment-baselinebaseline-shiftclip-pathclip-ruleclipPathUnitsmaskmaskUnitsmaskContentUnitsfilterfilterUnitsprimitiveUnitsmarker-startmarker-midmarker-endmarkerWidthmarkerHeightmarkerUnitsrefXrefYorientpatternUnitspatternContentUnitspatternTransformgradientUnitsgradientTransformspreadMethodoffsetstop-colorstop-opacityinin2resultstdDeviationflood-colorflood-opacityoperatork1k2k3k4modetypevalues

Additional attributes of individual SVG elements

  • <use>: hrefxlink:href
  • <image>: hrefxlink:href

Attributes with an address

  • <a href><a xlink:href>: A link with http, https, mailto, tel or a relative address. Any other target is removed, the link text stays.
  • <img src><video src><audio src><source src><track src><image href><image xlink:href>: Only an address from the media library (/cdn/assets/…). Otherwise the whole element is removed.
  • <video poster>: Only an address from the media library (/cdn/assets/…). Otherwise only the attribute is removed.
  • <use href><use xlink:href>: Only a reference within the content such as #dot. Otherwise the attribute is removed.
  • every SVG attribute: url() only as a reference within the content such as url(#gradient). If it holds any other address, the attribute is removed.
  • style: Addresses only from the media library, plus images and fonts as data:. The details are in the HTML section under “Addresses in CSS”.
Example: an SVG graphic with a gradient and a reference within the content
<div>
  <svg viewBox="0 0 320 80" role="img" aria-label="Welcome">
    <defs>
      <linearGradient id="gradient">
        <stop offset="0" stop-color="#12296b" />
        <stop offset="1" stop-color="#1a5c3a" />
      </linearGradient>
      <circle id="dot" r="10" />
    </defs>
    <rect width="320" height="80" rx="12" fill="url(#gradient)" />
    <use href="#dot" x="40" y="40" fill="white" />
    <text x="64" y="47" fill="white" font-size="22">Welcome</text>
  </svg>
</div>

Animation and length

Motion comes from CSS animations alone, in a <style> or in the style attribute, because the screen removes scripts. These animations determine the length of a content item.

How it is measured

  • An infinite loop (infinite) counts with its duration. Its delay only shifts where in the loop it starts and does not count.
  • A finite animation counts with delay plus duration times iterations: animation: title 5s 2s 3 gives 17 seconds.
  • If the content has several animations, the longest one counts.
  • The motion of the icon badges (classes starting with q-anim-) does not count.
  • If the content has several language versions, the longest of them counts.

The limit

Animated content may be at most 30 seconds long, the same limit as for a video. The editor shows the measured length below the preview and blocks saving while it is above the limit. A video is trimmed to the limit on upload, whereas animated content that is too long is rejected on saving: trimmed, its ending would silently be missing on the screen.

If a time value uses var(), calc() or a related function such as min(), max() or clamp(), the length cannot be determined, and the content is rejected on saving as well. Write duration and delay as fixed values in s or ms, or state the length yourself with data-duration.

On the screen

If the measured length is longer than 12 seconds, the content holds its zone for exactly one pass, like a video, and then the next content follows. A shorter animation holds nothing: the content changes at the usual pace, and a small loop such as a pulsing arrow simply keeps running while it is visible. This applies in every zone of the screen.

Example: a title fades in once, two lines alternate in a loop of 20 seconds
<div>
  <style>
    .title { animation: fade-in 2s ease-out 1s both; }
    .alternate { position: relative; }
    .alternate p { animation: show 20s linear infinite; }
    .alternate p + p { position: absolute; top: 0; animation-delay: -10s; }
    @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
    @keyframes show {
      0%, 45% { opacity: 1; }
      50%, 95% { opacity: 0; }
      100% { opacity: 1; }
    }
  </style>
  <h2 class="title">Autumn clean-up on Saturday</h2>
  <div class="alternate">
    <p>We meet at 9 am in the courtyard.</p>
    <p>Gloves and bags are provided.</p>
  </div>
</div>

Stating the length with data-duration

With the attribute data-duration you set the length of a content item yourself, for example <div data-duration="20s">. The statement wins over the measured animations, even if they would be longer or could not be determined; var() and calc() in the animations then no longer matter for the length. It also applies to content without any animation, which then stays in its zone for exactly that long. Unlike a measured length, a stated length holds the zone even when it is below 12 seconds.

Where it has to go

On the outermost element, meaning the first element in the source. A <style>, a <script> and comments before it are skipped. In Markdown the first HTML element in the raw text counts, even if a heading with # stands above it. On an inner element the statement has no effect.

Valid values

A number with s or ms, for example 20s, 1500ms or 12.5s. A number without a unit, a space between number and unit, a comma instead of the point and the value zero are invalid. With an invalid value the editor blocks saving and names the value. The limit of at most 30 seconds applies to the statement as well.

Example in HTML: 20 seconds without animation
<div data-duration="20s">
  <h2>Residents' meeting</h2>
  <p>Thursday, 7 pm, in the common room.</p>
</div>
Example in Markdown: the statement on the first HTML element
<div data-duration="15s">

# Lift under maintenance

Please use the stairs until Friday.

</div>

The trap: <style> as the first element

If a <style> is the first element in the source, the browser moves it into the head of the document while parsing, and the screen discards it there. The animations are then missing, and the editor measures no length either. The preview in the editor shows the same, so you see it before saving.

The remedy is a wrapping element: put the whole content including the <style> into a <div>. The same applies in Markdown when the text starts with a <style>.

This way the <style> is dropped
<style>
  .title { animation: fade-in 2s both; }
  @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
</style>
<h2 class="title">Welcome</h2>
This way it is kept
<div>
  <style>
    .title { animation: fade-in 2s both; }
    @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
  </style>
  <h2 class="title">Welcome</h2>
</div>

Back to the help center