Show table of contents Hide table of contents

What's Up?

Up is a markup language for writing structured documents in plain text.

For software developers, Up offers a software library that converts Up markup into HTML. To learn more, please see Using the Up library.


Why use Up?

Up isn't the only markup language that produces HTML. What makes it special?

Up uses customizable keywords

Too many markup languages devolve into a dense soup of symbols and punctuation.

When a keyword would provide more clarity than a symbol, Up takes advantage of that! Several writing conventions, including Tables and Revealable content, incorporate keywords.

If you're a software developer using the Up library, you can provide multiple custom variations for each keyword. To learn more, please see Customizing keywords.

Up has a flexible, forgiving syntax

Up recognizes Numbered lists that count backwards.

Markup
3) Buy milk
2) Buy bread
#) Buy happiness
Output
  1. Buy milk

  2. Buy bread

  3. Buy happiness

Up usually ignores Excessive delimiter characters.

For example, you don't need to perfectly balance asterisks when stressing or emphasizing text.

Markup
I ***love****** asterisks!
Output

I love asterisks!

Up isn't picky about which brackets you use for Links.

Markup
- Buy [milk] (en.wikipedia.org/wiki/Milk)
- Buy (bread) [en.wikipedia.org/wiki/Bread]
- Buy [sugar] [en.wikipedia.org/wiki/Sugar]
- Buy (happiness) (en.wikipedia.org/wiki/Happiness)
Output

Up even supports Overlapping writing conventions!

Markup
John **enjoys ==sleeping** late== whenever he can.
Output

John enjoys sleeping late whenever he can.

Up produces fully accessible HTML

From the table of contents to the last movie-ruining spoiler, Up produces fully accessible HTML. This means people who have trouble viewing a screen or a using mouse can enjoy every document.


Why not use Up?

You want a rich ecosystem of tools

So far, there is only one software library for Up, written and maintained by a single person. In contrast, other markup languages have countless tools and plugins.

You need speed

Up is not terribly slow, but it's not terribly fast, either—at least not yet! If you need instant, real-time parsing and rendering of large documents, Up isn't the best markup language for you.


Writing conventions

Don't get lost! The following terms are occasionally used throughout this section.

Writing convention

Any special annotation or formatting recognized by Up.

Inline writing convention

Any writing convention that can be used within paragraphs. This includes Emphasis and Highlighting.

Outline writing convention

Any non-inline writing convention. This includes Paragraphs and Tables.

Paragraphs

Paragraphs are the simplest writing convention in Up.

Markup
Unlike regular dental floss, you can use floss picks even if you're not a trained dental hygienist.

Floss picks are sold in stylish, resealable plastic bags. You have no excuse not to buy some today.
Output

Unlike regular dental floss, you can use floss picks even if you're not a trained dental hygienist.

Floss picks are sold in stylish, resealable plastic bags. You have no excuse not to buy some today.

To produce a paragraph, write a line of text. That's all there is to it!

Typically, paragraphs are separated by one or two blank lines. Three or more blank lines between paragraphs indicates a meaningful change of subject. To learn more, see Thematic breaks.

In contrast, consecutive non-blank lines produce Line blocks, not consecutive paragraphs.

Line blocks

Use the line block convention for addresses, lyrics, or anything consisting of lines instead of actual Paragraphs.

Markup
Have you read my new poem?

Roses are red
Violets *aren't* blue
Lyrics have lines
And addresses do, too

Poetry is just too easy.
Output

Have you read my new poem?

Roses are red
Violets aren't blue
Lyrics have lines
And addresses do, too

Poetry is just too easy.

Consecutive non-blank lines produce a line block, unless those lines represent another writing convention, like Numbered lists.

Emphasis

Use the emphasis convention to emphasize a word or phrase.

If the reader should pronounce a word or phrase differently (e.g. to indicate contrast or sarcasm), consider emphasizing it.

Markup
Only eat the *green* grapes. The red grapes are for Pikachu.
Output

Only eat the green grapes. The red grapes are for Pikachu.

To emphasize text, enclose it within single asterisks.

Like most inline writing conventions, emphasis can be nested within itself.

Markup
John really, *really, *really** hates Red Delicious apples.
Output

John really, really, really hates Red Delicious apples.

Stress

Use the stress convention to indicate a word or phrase is particularly important.

If the reader should raise their voice while reading a word or phrase, consider stressing it.

Markup
Do **not** step on the dinosaur!
Output

Do not step on the dinosaur!

To stress text, enclose it within double asterisks.

Like most inline writing conventions, stress can be nested within itself.

Markup
John really, **really, **really**** hates Red Delicious apples.
Output

John really, really, really hates Red Delicious apples.

Italics

Use the italic convention to stylistically offset a word or phrase from the surrounding text without conveying emphasis. The titles of books and movies should probably be italicized.

If you want to emphasize text, see Emphasis.

Markup
My favorite video game is _Chrono Cross_.
Output

My favorite video game is Chrono Cross.

To italicize text, enclose it within single underscores.

Like most inline writing conventions, italicized text can be nested within itself.

Markup
My favorite show is _Real Recipes _Redux_: Super Suppers_.
Output

My favorite show is Real Recipes Redux: Super Suppers.

Bold

Typically, people use bold text to convey extra importance—that's what the Stress convention is for!

To make a word or phrase bold without conveying any extra importance, use the plain old bold convention.

Markup
Has anyone actually used __KABOOM__ cleaning products?
Output

Has anyone actually used KABOOM cleaning products?

To make text bold, enclose it within double underscores.

Like most inline writing conventions, bold text can be nested within itself.

Markup
We've all seen the ads.

__No hard scrubbing! __KABOOM__... and the stains are gone!__
Output

We've all seen the ads.

No hard scrubbing! KABOOM… and the stains are gone!

Highlighting

To draw attention to text without altering its semantics, using the highlighting convention.

Highlighting should not be used to emphasize or stress text! If that's your purpose, see Emphasis or Stress.

Markup
Our cupcakes are organic, ==gluten-free==, and made using only the most expensive ingredients.
Output

Our cupcakes are organic, gluten-free, and made using only the most expensive ingredients.

To highlight text, enclose it within two or more equal signs.

Like most inline writing conventions, highlighting can be nested within itself.

Markup
Our cupcakes are ==organic, ==gluten-free==, vegan==, and made using only the most expensive ingredients.
Output

Our cupcakes are organic, gluten-free, vegan, and made using only the most expensive ingredients.

Links

You already know what a link is!

Markup
The [Game Boy] (en.wikipedia.org/wiki/Game_Boy) was my first video game system.
Output

The Game Boy was my first video game system.

A link consists of two parts: content and a URL.

To produce a link, simply enclose its content in square brackets or parentheses, then enclose its URL in square brackets or parentheses.

You can use mix and match either type of bracket—they're totally interchangeable.

Markup
- Buy [milk] (en.wikipedia.org/wiki/Milk)
- Buy (bread) [en.wikipedia.org/wiki/Bread]
- Buy [sugar] [en.wikipedia.org/wiki/Sugar]
- Buy (happiness) (en.wikipedia.org/wiki/Happiness)
Output

As demonstrated above, you can omit a link's URL scheme.1 If you do, Up uses https:// for the URL scheme.

1
http:// and https:// are examples of URL schemes.

If you're a software developer using the Up library, you can specify a different default URL scheme. To learn more, see defaultUrlScheme (setting).

Other settings affecting links are:

Links with URLs containing spaces

If your link URL contains spaces, Up assumes you aren't actually trying to produce a link. So it avoids producing one!

Markup
Warlocked is the best game for GameBoy [sic] (other than Pokémon).
Output

Warlocked is the best game for GameBoy [sic] (other than Pokémon).

If your link URL really does contain spaces, you can make it clear that you intend to produce a link by omitting the space between your link's content and its URL.

Markup
I love the [music](duckduckgo.com/?q=chrono cross music) for Chrono Cross.
Output

I love the music for Chrono Cross.

When you omit the space between your link's content and its URL, Up always produces a link.

These rules also apply when Linkifying another writing convention.

Bare URLs

Alternatively, if you include a bare URL in your document, Up will automatically produce a link for you.

Markup
https://en.wikipedia.org/wiki/John_Carmack
Output

en.wikipedia.org/wiki/John_Carmack

Inline quotes

Up automatically recognizes quoted text.

If you want to quote more a few sentences, considering using Blockquotes.

Markup
"Only eat the green grapes," John said.
Output

Only eat the green grapes, John said.

You already know how to use quotation marks! Just keep doing what you're doing.

Like most inline writing conventions, inline quotes can be nested within themselves.

Markup
Bob replied, "Yesterday, Harvey yelled "I'll take the case!", but I doubt he will."
Output

Bob replied, Yesterday, Harvey yelled I'll take the case!, but I doubt he will.

Parenthetical text

Up automatically recognizes parenthetical text.

Markup
When I was ten years old, I left my home (in Pallet Town) to search for Pokémon.
Output

When I was ten years old, I left my home (in Pallet Town) to search for Pokémon.

Up understands that text enclosed within parentheses or square brackets represents supplemental content.

Example user input

Use the example user input convention to represent user input, including:

Markup
  Press {esc} to quit.
Output

Press esc to quit.

To indicate that text represents user input, enclose the text within curly brackets.

Up ignores any spaces separating the curly brackets from the content they enclose.

Markup
Press { Start Game } when you are ready.
Output

Press Start Game when you are ready.

Within example user input, most writing conventions are ignored. However, Typographical writing conventions are supported.

Inline code

Use the inline code convention to represent a small fragment of computer code.

When you need to represent more than a small fragment of computer code, use Code blocks instead.

Markup
In HTML, you probably shouldn't use the `<font>` element.
Output

In HTML, you probably shouldn't use the <font> element.

To produce inline code, enclose text within an equal number of backticks on either side. You can use any number of backticks—simply make sure both sides match.

Markup
In HTML, you probably shouldn't use the ``<font>`` element.
Output

In HTML, you probably shouldn't use the <font> element.

Within inline code, other writing conventions are ignored. Characters that normally have special meaning are preserved as plain text.

Markup
In Up, surround text with `*asterisks*` to emphasize it.
Output

In Up, surround text with *asterisks* to emphasize it.

Including backticks in your code

To include backticks within inline code, you can precede each backtick with a backslash.

Markup
`let output = \`score:\` + 5`
Output

let output = `score:` + 5

For more information about the behavior of backslashes, see Disabling special characters.

Alternatively, inline code can contain streaks of backticks that aren't exactly as long as the inline code's outer delimiters. No backslashes are necessary.

In this example, the delimiters are 1 backtick long, so the inline code can contain streaks of 2 backticks:

Markup
`let output = ``score:`` + 5`
Output

let output = ``score:`` + 5

In this example, the delimiters are 2 backticks long, so the inline code can contain streaks of 1 backtick:

Markup
``let output = `score:` + 5``
Output

let output = `score:` + 5

Code starting or ending with backticks

If your inline code starts or ends with backticks, place a single space between the offending backticks and the outer delimiter. This single space is trimmed away.

In this example, the inline code both starts and ends with a backtick:

Markup
`` `inline_code` ``
Output

`inline_code`

Any spaces beyond that single space are preserved—if there are multiple spaces between the delimiter and the starting/ending backticks, only one space is trimmed away.

Markup
``    `inline_code`    ``
Output

`inline_code`

Furthermore, that single space is only trimmed away when it's necessary to separate a delimiter from backticks in your inline code. If a given side of inline code has any non-space characters between the delimiter and the outermost backtick, no spaces are trimmed from that side.

Markup
`` (`inline_code`) ``
Output

(`inline_code`)

Headings

Use headings to introduce a new section in the document.

Markup
Example heading
===============
Output

Example heading

If text is underlined, it's treated as a heading. The underline can consist of any combination of the following characters (you can mix and match):

A heading's underline must be at least three characters long, but it does not need to be the same length as the text of the heading.

Markup
Example heading with a short underline
===
Output

Example heading with a short underline

Heading levels

The first heading in a document is always a top-level heading. All subsequent headings with underlines consisting of the same characters are considered top-level.

The first heading with a different combination of underline characters is considered a second-level heading. Unsurprisingly, all subsequent headings with underlines consisting of the same characters are also considered second-level.

This process continues ad infinitum. Every new combination of heading underline characters introduces a new heading level. There is no limit to the number of heading levels in a document.

Headings with overlines

A heading can have an optional overline, but its overline must consist of the same combination of characters as its underline.

Markup
--------------------------------
Example heading with an overline
--------------------------------
Output

Example heading with an overline

For the purpose of determining heading levels, a heading with an overline is always considered distinct from a heading without one, even if both headings use the same combination of underline characters.

Therefore, a heading with an overline will never have the same level as a heading without an overline.

Section links

Use the section link convention to link to another section (heading) in your document.

Markup
Up even supports [topic: overlapping]!
Output

Up even supports Overlapping writing conventions!

To link to a heading, choose a unique snippet of markup from that heading's content line.2 Enclose that markup snippet within square brackets or parentheses, then insert topic: or section: directly inside your opening bracket.

2
Don't worry about the heading's underline or overline! Section links ignore both.

Up automatically matches your snippet to the most appropriate heading, then produces a link for you.

Matching the most appropriate heading

Initially, Up tries to match your section link to the first heading whose content line's markup exactly matches your snippet.3 If there isn't an exact match, Up matches your section link to the first heading whose content line markup contains your snippet.

3
Up totally ignores the capitalization of section links' markup snippets, so a section link and a heading can be an exact match without being capitalized the same way.

Footnotes

Use the footnote convention for asides or citations—anything you want to say without breaking the flow of a paragraph.

Footnotes are automatically extracted into blocks for you.

Markup
Warlocked [^ No relation to Warcraft!] is a real-time strategy game.
Output

Warlocked4 is a real-time strategy game.

4
No relation to Warcraft!

To produce a footnote, enclose its content within parentheses or square brackets. Then, insert a caret ^ directly after your opening bracket.

Media

Up allows you to embed Images, Video, or Audio in your document.

Images

Markup
[image: Super Mario Land box art] (i.imgur.com/TxlFlkX.jpg)
Output
Super Mario Land box art

If you want to link your image to another page, please see Linkifying another writing convention.

Video

Markup
[video: Professor Leonard] (i.imgur.com/32fBpnh.mp4)
Output

Audio

Markup
[audio: Sadness theme from Infinity for Game Boy] (a.clyp.it/ybct5hcl.mp3)
Output

Syntax

To embed media in your document, simply enclose its description in square brackets or parentheses, then enclose its URL in square brackets or parentheses.

You can use mix and match either type of bracket—they're totally interchangeable.

Media descriptions

Media descriptions always start with image:, audio:, or video:, depending on the type of media you wish to include.

Within media descriptions, most writing conventions are ignored. However, Typographical writing conventions are supported.

Media URLs

As demonstrated above, you can omit the URL scheme for media URLs. If you do, Up uses https:// for the URL scheme.

If you're a software developer using the Up library, you can specify a different default URL scheme. To learn more, see defaultUrlScheme (setting).

Other settings affecting media are:

Revealable content

Both Inline revealables and Revealable blocks recognize any of the following keywords:

Like all keywords in Up, you can capitalize them however you want.

Inline revealables

Use the inline revealable convention to hide content within a paragraph.

When you want to hide more than a sentence or two, use Revealable blocks instead.

Markup
At the end of Pokémon Red, [SPOILER: you battle your rival] before the credits roll.
Output

At the end of Pokémon Red, you battle your rival before the credits roll.

To hide content within a paragraph, first enclose that content within square brackets or parentheses.

Then, directly inside your opening bracket, insert one of the revealable keywords followed by a colon: spoiler:, nsfw:, nsfl:, or revealable:.

Inline revealables can contain any inline writing convention.

Revealable blocks

Use revealable block convention to hide a block of content.

When you want to hide content within a paragraph, use Inline revealables instead.

Markup
SPOILER:
  After defeating the Elite Four at the end of Pokémon Red, you still have to battle your rival one last time.

  Your rival's specific lineup depends on the Pokémon you selected at the beginning of the game. However, his first three Pokémon are always the same:

  1. Pidgeot
  2. Alakazam
  3. Rhydon
Output

After defeating the Elite Four at the end of Pokémon Red, you still have to battle your rival one last time.

Your rival's specific lineup depends on the Pokémon you selected at the beginning of the game. However, his first three Pokémon are always the same:

  1. Pidgeot

  2. Alakazam

  3. Rhydon

To hide a block of content, first indent it two spaces (or a tab).

Then, on the line before your indented block, put one of the revealable keywords: spoiler, nsfw, nsfl, or revealable.

In the example above, the chosen revealable keyword (spoiler) is followed by a colon. The colon is optional.

Blockquotes

Use the blockquote convention to quote a large section of text.

For typical dialog, you should probably use Inline quotes instead.

Markup
> I hate oranges for the following reasons:
>
> 1. They're not apples.
> 2. They're not bananas.
Output

I hate oranges for the following reasons:

  1. They're not apples.

  2. They're not bananas.

A blockquote consists of consecutive lines starting with > (a greater-than symbol followed by a space).

Blockquotes can contain any outline writing convention, including other blockquotes.

Markup
> Thank you for replying to my blog!
>
> > I hate oranges for the following reasons:
> >
> > 1. They're not apples.
> > 2. They're not bananas.
>
> I completely understand.
Output

Thank you for replying to my blog!

I hate oranges for the following reasons:

  1. They're not apples.

  2. They're not bananas.

I completely understand.

Thematic breaks

Use the thematic break convention to represent a change of subject.

A thematic break can be represented by 3 or more consecutive blank lines.

Markup
I vowed never to eat apples again.



By mid-March, a second flock of birds had moved into my dining room.
Output

I vowed never to eat apples again.


By mid-March, a second flock of birds had moved into my dining room.

A thematic break can also be represented by a line consisting of 3 or more of the following characters:

You can use any combination of those characters!

Markup
I vowed never to eat apples again.

#=*=*=*=*=*=*=*=*=*=#

By mid-March, a second flock of birds had moved into my dining room.
Output

I vowed never to eat apples again.


By mid-March, a second flock of birds had moved into my dining room.

Bulleted lists

You already know what a bulleted list is!

Markup
- Buy milk
- Buy bread
- Buy happiness
Output
  • Buy milk

  • Buy bread

  • Buy happiness

Bullets

In a bulleted list, each item starts with a bullet character followed by a space. The following characters can serve as a bullet:

Spacing between list items

Each bulleted list item can be followed by a single blank line.

Markup
- Buy milk

- Buy bread

- Buy happiness
Output
  • Buy milk

  • Buy bread

  • Buy happiness

On the other hand, if a list item is followed by 2 blank lines, it marks the end of the list.

Markup
- Buy milk
- Buy bread


- Fix squeaky cabinet
- Fix self-esteem
Output
  • Buy milk

  • Buy bread

  • Fix squeaky cabinet

  • Fix self-esteem

List items consisting of multiple lines

List items aren't limited to a single line! Bulleted lists can contain any outline writing convention, including other bulleted lists.

If your list item contains more than one line, subsequent lines should be indented 2 spaces (or a tab).

Markup
- Buy milk.

  If whole milk is on sale, buy that. Otherwise, buy 2%.

- Buy bread.

  Only buy bread from one of the following brands:

  * Little Northern Bakehouse
  * Udi's
  * Canyon Bakehouse

- Buy happiness.

  Don't spend more than a few cents on this.
Output
  • Buy milk.

    If whole milk is on sale, buy that. Otherwise, buy 2%.

  • Buy bread.

    Only buy bread from one of the following brands:

    • Little Northern Bakehouse

    • Udi's

    • Canyon Bakehouse

  • Buy happiness.

    Don't spend more than a few cents on this. Not worth it.

Numbered lists

You already know what a numbered list is!

Markup
1. Buy milk
2. Buy bread
3. Buy happiness
Output
  1. Buy milk

  2. Buy bread

  3. Buy happiness

Numbered lists are nearly identical to Bulleted lists—the only difference is that numbered list items have ordinals, not bullets.

The ordinal for a numbered list item can be expressed several ways:

Like each bullet in a bulleted list, each ordinal in a numbered list must be followed by a space.

Lists starting at a specific number

Numbered lists don't have to start at 1.

Markup
3) March
#) April
#) May
Output
  1. March

  2. April

  3. May

Lists in descending order

Up automatically recognizes when a numbered list is in descending order.

If a numbered list has at least two items with integer ordinals (as opposed to number signs), and if the first integer is greater than the second, Up considers the list to be in descending order.

Markup
3) Buy milk
2) Buy bread
#) Buy happiness
Output
  1. Buy milk

  2. Buy bread

  3. Buy happiness

Single-item numbered lists

Like bulleted lists, numbered lists can consist of a single item.

Markup
1) Buy milk
Output
  1. Buy milk

There's a small exception to this rule: If your list item's ordinal is expressed as an integer followed by a period (e.g. 1.), you must have more than one list item. This exception helps prevent accidental numbered lists.

Markup
1783. Not a good year for Great Britain.
Output

1783. Not a good year for Great Britain.

Description lists

Use description lists represent a collection of subjects and their descriptions.

You can use description lists for:

Markup
Kirby's Dreamland
  A video game about a flying marshmallow.

Super Mario Land
  A video game about a jumping plumber.
Output
Kirby's Dreamland

A video game about a flying marshmallow.

Super Mario Land

A video game about a jumping plumber.

Every item in a description list consists of two parts:

  1. One or more subjects

  2. A single description of those subjects

Subjects

Subjects can contain any inline writing convention.

Markup
`<ol>`
  An HTML element representing numbered lists.

`<ul>`
  An HTML element representing bulleted lists.
Output
<ol>

An HTML element representing numbered lists.

<ul>

An HTML element representing bulleted lists.

When there is more than one subject for a given description, they should be listed consecutively, one subject per line.

Markup
Game Boy Light
Game Boy Pocket
Game Boy Color
  Handheld videogame systems released by Nintendo in the 1990s.
Output
Game Boy Light
Game Boy Pocket
Game Boy Color

Handheld videogame systems released by Nintendo in the 1990s.

Descriptions

Each description follows the subjects it describes.

Descriptions are indented 2 spaces (or a tab). They can contain any outline writing convention, including other description lists.

Markup
Bulbasaur
  A plant Pokémon with a bulb growing from its back.

  Height
    0.7 m
  Weight
    6.9 kg

Charmander
  A fire Pokémon with a flame on its tail.

  Height
    0.6 m
  Weight
    8.5 kg
Output
Bulbasaur

A plant Pokémon with a bulb growing from its back.

Height

0.7 m

Weight

6.9 kg

Charmander

A fire Pokémon with a flame on its tail.

Height

0.6 m

Weight

8.5 kg

Each description may be followed by an optional blank line. If a description is followed by two blank lines, it marks the end of the description list.

Markup
Lime
  A green fruit.
Strawberry
  A red fruit.


Bulbasaur
  A green Pokémon.
Charmander
  A red Pokémon.
Output
Lime

A green fruit.

Strawberry

A red fruit.

Bulbasaur

A green Pokémon.

Charmander

A red Pokémon.

Tables

You already know what a table is! Use tables to display rows of data organized into columns.

Markup
Table: Moves learned by the Pokémon Bulbasaur

Move;         Type;     Power;  Accuracy

Tackle;       Normal;   50;     100%
Growl;        Normal;   ;       100%
Leech Seed;   Grass;    ;       90%
Vine Whip;    Grass;    45;     100%
Output
Moves learned by the Pokémon Bulbasaur
MoveTypePowerAccuracy
TackleNormal50100%
GrowlNormal100%
Leech SeedGrass90%
Vine WhipGrass45100%

A table consists of:

Table cells are separated by semicolons. To learn more, see Cells.

Our examples use extra spaces to align cells. This makes our markup more readable, but it's strictly optional! If you want, you can squish your cells together, as long as any empty cells contain at least one space. To learn more, please see Empty cells.

Squished markup
Table: My favorite fruits

Fruit;Color;Taste

Lime;Green;Sour
Lemon;Yellow;Sour
Banana;Yellow;Sweet
Output
My favorite fruits
FruitColorTaste
LimeGreenSour
LemonYellowSour
BananaYellowSweet

The caption

The text after Table: is treated as the table's caption. Captions can contain any inline writing convention.

Markup
Table: My favorite [fruits] (en.wikipedia.org/wiki/Fruit)

Fruit;      Color;      Taste

Lime;       Green;      Sour
Lemon;      Yellow;     Sour
Banana;     Yellow;     Sweet
Output
My favorite fruits
FruitColorTaste
LimeGreenSour
LemonYellowSour
BananaYellowSweet

Captions are strongly encouraged, but they're not required. To create a table without a caption, simply put Table on its own line.

Markup
Table

Fruit;      Color;      Taste

Lime;       Green;      Sour
Lemon;      Yellow;     Sour
Banana;     Yellow;     Sweet
Output
FruitColorTaste
LimeGreenSour
LemonYellowSour
BananaYellowSweet

Cells

Table cells are separated by semicolons. If you want to include a semicolon in a cell, simply put a backslash before it. To learn more, see Disabling special characters.

Markup
Table: My favorite fruits

Fruit;      Reason for liking

Apples;     Easy to eat\; stylish
Grapes;     Each grape is very cheap
Oranges;    The color orange is nice
Output
My favorite fruits
FruitReason for liking
ApplesEasy to eat; stylish
GrapesEach grape is very cheap
OrangesThe color orange is nice

Cells spanning multiple columns

If you want a cell to span two columns, terminate that cell with two semicolons.

Markup
Table: My favorite fruits

Fruit;      Color;      Taste

Lime;       Green;      Sour
Orange;;                Sweet and tart
Banana;     Yellow;     Sweet
Output
My favorite fruits
FruitColorTaste
LimeGreenSour
OrangeSweet and tart
BananaYellowSweet

Likewise, if you want a cell to span six columns, terminate that cell with six semicolons.

Empty cells

A cell consisting solely of spaces (one or more) is considered empty.

Normally, you have to put at least one space in the cell, because consecutive semicolons indicate that you want the previous cell to span multiple columns.

However, to indicate that the first cell in a row should be empty, simply start that row with a semicolon. You don't need to put any spaces before it.

Markup
Table: Games in the Chrono series

Release Date;       Game;

March 11, 1995;     Chrono Trigger
November 18, 1999;  Chrono Cross
;                   Chrono Break
Output
Games in the Chrono series
Release DateGame
March 11, 1995Chrono Trigger
November 18, 1999Chrono Cross
Chrono Break

Likewise, to indicate that the last cell in a row should be empty, simply end that row with a semicolon. You don't need to add any spaces after it.

Markup
Table: Games in the Chrono series

Game;               Release Date

Chrono Trigger;     March 11, 1995
Chrono Cross;       November 18, 1999
Chrono Break;
Output
Games in the Chrono series
GameRelease Date
Chrono TriggerMarch 11, 1995
Chrono CrossNovember 18, 1999
Chrono Break

The header row

The header defines each column in the table.

The single blank lines before and after the header are not required.

Markup
Table: Moves learned by the Pokémon Bulbasaur
Move;         Type;     Power;  Accuracy
Tackle;       Normal;   50;     100%
Growl;        Normal;   ;       100%
Leech Seed;   Grass;    ;       90%
Vine Whip;    Grass;    45;     100%
Output
Moves learned by the Pokémon Bulbasaur
MoveTypePowerAccuracy
TackleNormal50100%
GrowlNormal100%
Leech SeedGrass90%
Vine WhipGrass45100%

Cells in a table's header can contain any inline writing convention.

Content rows

The content rows of a table follow its header row. The content rows contain the table's actual data.

If a content row is followed by a blank line, it ends the table.

Markup
Table: Moves learned by the Pokémon Bulbasaur

Move;         Type;     Power;  Accuracy

Tackle;       Normal;   50;     100%
Growl;        Normal;   ;       100%
Leech Seed;   Grass;    ;       90%
Vine Whip;    Grass;    45;     100%

I love Bulbasaur!
Output
Moves learned by the Pokémon Bulbasaur
MoveTypePowerAccuracy
TackleNormal50100%
GrowlNormal100%
Leech SeedGrass90%
Vine WhipGrass45100%

I love Bulbasaur!

Content row cells can contain any inline writing convention.

Including a header column in your table

To indicate your table has a header column, simply indent its header row at least two spaces (or a tab).

When you indent a table's the header row, Up automatically treats the first cell in each subsequent row as the header column.

Markup
Table: Moves learned by the Pokémon Bulbasaur

              Type;     Power;  Accuracy

Tackle;       Normal;   50;     100%
Growl;        Normal;   ;       100%
Leech Seed;   Grass;    ;       90%
Vine Whip;    Grass;    45;     100%
Output
Moves learned by the Pokémon Bulbasaur
TypePowerAccuracy
TackleNormal50100%
GrowlNormal100%
Leech SeedGrass90%
Vine WhipGrass45100%

When your table has a header column, Up automatically inserts an extra blank cell at the beginning of the header row in the top level corner, above the header column.

Code blocks

Use the code block convention to represent a block of computer code.

When you need to represent only a small fragment of computer code, consider using Inline code instead.

Markup
```
function nthFibonacci(n: number): number {
  return n <= 2
    ? n - 1
    : nthFibonacci(n - 1) + nthFibonacci(n - 2)
}
```
Output
function nthFibonacci(n: number): number {
  return n <= 2
    ? n - 1
    : nthFibonacci(n - 1) + nthFibonacci(n - 2)
}

Code blocks are surrounded (underlined and overlined) by matching streaks of 3 or more backticks.

If there is no matching end streak, the code block extends to the end of the document (or to the end of the current outline writing convention, if the code block is nested within one).

Within a code block, indentation is preserved, and every single character is treated literally. No other writing conventions are recognized, which means code blocks don't support Disabling special characters.

Including streaks of backticks

Code blocks can contain streaks of backticks that aren't exactly as long as the enclosing streaks.

Markup
``````
A code block:

```
function factorial(n: number): number {
  return n <= 1
    ? 1
    : n * factorial(n - 1)
}
```

See? Not so hard!
``````
Output
A code block:

```
function factorial(n: number): number {
  return n <= 1
    ? 1
    : n * factorial(n - 1)
}
```

See? Not so hard!

Linkifying another writing convention

You can put Images inside of Links, but the syntax can be a bit messy.

Messy markup
[(image: Warlocked box art) (i.imgur.com/879AeYU.jpg)] [en.wikipedia.org/wiki/Warlocked]
Output
Warlocked box art

That's a lot of brackets! Luckily, there's a shortcut.

Simply place the linkifying URL after the image's own URL, and Up will produce a link for you.

Cleaner markup
[image: Warlocked box art] [i.imgur.com/879AeYU.jpg] (en.wikipedia.org/wiki/Warlocked)
Output
Warlocked box art

When linkifying an image, you can mix and match square brackets and parentheses—they're totally interchangeable.

This shortcut also works for the following inline writing conventions:

Example user input
Markup
Press {space} (en.wikipedia.org/wiki/Space_bar) to continue.
Output

Press space to continue.

Footnotes
Markup
Pokémon is old [^ Released in 1996!] (en.wikipedia.org/wiki/Pokémon_Red_and_Blue) but it maintains its charm.
Output

Pokémon is old5 but it maintains its charm.

Inline revealables
Markup
At the end of Pokémon Red, [SPOILER: you battle your rival] (pokemon.wikia.com/wiki/Rival) before the credits roll.
Output

At the end of Pokémon Red, you battle your rival before the credits roll.

5
Released in 1996!

Typographical writing conventions

Ellipsis

Consecutive periods represent an ellipsis, so Up replaces them with a fancy ellipsis character.

Markup
I don't know... I doubt a spider would do this.
Output

I don't know… I doubt a spider would do this.

If you're a software developer using the Up library, you can specify a different fancy ellipsis (e.g. ). To learn more, see fancyEllipsis (setting).

En dash

Two consecutive hyphens produce an en dash.

Markup
I agree -- to an extent -- with your plan to eat nothing but cereal.
Output

I agree – to an extent – with your plan to eat nothing but cereal.

Em dash

Three consecutive hyphens produce an em dash.

Markup
Use a spoon---a fork won't cut it.
Output

Use a spoon—a fork won't cut it.

Plus-minus sign

A plus sigh followed by a hyphen produces a plus-minus sign.

Markup
I ate 5 waffles +- 2.
Output

I ate 5 waffles ± 2.

Excessive delimiter characters

For Emphasis, Stress, Italics, Bold, Highlighting, and Inline quotes, Up ignores any excessive delimiter characters.

Markup
This organic, ====gluten-free==== cupcake is too expensive.
Output

This organic, gluten-free cupcake is too expensive.

This includes when delimiter characters aren't perfectly balanced on either side.

Markup
My favorite video game is _Chrono Cross__.
Output

My favorite video game is Chrono Cross.

Disabling special characters

To disable the special meaning of a character, put a backslash before it.

Markup
I love \*asterisks*!
Output

I love *asterisks*!

Likewise, to disable the special meaning of a backslash, put another backslash before it.

Markup
My favorite kind of slash is the backslash: \\. What is yours?
Output

My favorite kind of slash is the backslash: \. What is yours?

Overlapping writing conventions

In Up, inline writing conventions can freely overlap.

Markup
John **enjoys ==sleeping** late== whenever he can.
Output

John enjoys sleeping late whenever he can.

Superficial overlapping

If conventions overlap superficially—by only their start or end delimiters—Up pretends they weren't overlapped at all.

Markup
At the end of Pokémon Red, [SPOILER: you battle your rival *yet again]* before the credits roll.
Output

At the end of Pokémon Red, you battle your rival yet again before the credits roll.


Using the Up library

The Up library can be found on NPM.

Installation

npm install up-lang --save

Usage Overview

Typically, you'll want to use one of the various Functions exported by the library.

const { parseAndRender } = require('up-lang')

const html = parseAndRender(markup, optionalSettings)

Alternatively, you can use the exported Up class, which can be helpful if you need to parse or render several documents sharing custom settings. Please see Up (class) to learn more.

If you plan to modify or analyze a parsed document, you'll want to check out the Abstract syntax tree classes.

Functions

parseAndRender (function)

This function converts Up markup into HTML and returns the result.

Arguments
markup: string

The Up markup to convert into HTML.

settings (optional): Settings (interface)

The custom parsing and/or rendering settings to apply.

Return type: string

This function returns HTML representing the rendered document.

Usage
Without custom settings
const html = parseAndRender(markup)
With custom settings
const html = parseAndRender(markup, {
  parsing: {
    createSourceMap: true,
    keywords: { audio: "listen" }
  },
  rendering: {
    idPrefix: "article"
  }
})

parseAndRenderWithTableOfContents (function)

This function converts Up markup into two pieces of HTML, both of which are returned:

  1. A table of contents

  2. The document itself

Arguments
markup: string

The Up markup to parse and render.

settings (optional): Settings (interface)

The custom parsing and/or rendering settings to apply.

Return type: DocumentAndTableOfContentsHtml (interface)

This function returns HTML representing the rendered document and table of contents.

Usage
Without custom settings
const { tableOfContentsHtml, documentHtml } =
  parseAndRenderWithTableOfContents(markup)
With custom settings
const { tableOfContentsHtml, documentHtml } =
  parseAndRenderWithTableOfContents(markup, {
    parsing: {
      createSourceMap: true,
      keywords: { audio: "listen" }
    },
    rendering: {
      idPrefix: "article",
      terms: { reveal: "expand" }
    }
  })

DocumentAndTableOfContentsHtml (interface)

This interface represents the HTML for a rendered document and its table of contents.

Members
tableOfContentsHtml: string

The HTML for the table of contents.

documentHtml: string

The HTML for the document itself.

Notes

The following functions return an object satisfying this interface:

parseAndRenderInline (function)

This function converts inline Up markup into inline HTML and returns the result.

To learn more about inline documents, see Inline documents.

Arguments
inlineMarkup: string

The inline Up markup to convert into inline HTML.

parsingSettings (optional): Settings (interface)

The custom parsing and/or rendering settings to apply.

Return type: string

This function returns HTML representing the rendered inline document.

Usage
Without custom settings
const html = parseAndRenderInline(markup)
With custom settings
const html = parseAndRenderInline(markup, {
  parsing: {
    baseForUrlsStartingWithSlash: "https://example.com/en-us",
    keywords: { audio: "listen" }
  },
  rendering: {
    idPrefix: "byline",
    terms: {
      footnoteReference: "footnote mention",
      reveal: "show"
    }
  }
})

parse (function)

This function parses Up markup and returns the resulting syntax tree.

Arguments
markup: string

The Up markup to parse.

parsingSettings (optional): Settings.Parsing (interface)

The custom parsing settings to apply.

Return type: Document (class)

This function returns a syntax tree representing the parsed document.

Usage
Without custom settings
const html = parse(markup)
With custom settings
const document = parse(markup, {
  createSourceMap: true,
  keywords: { audio: "listen" }
})

parseInline (function)

This function parses inline Up markup and returns the resulting inline syntax tree.

To learn more about inline documents, see Inline documents.

Arguments
inlineMarkup: string

The inline Up markup to parse.

parsingSettings (optional): Settings.Parsing (interface)

The custom parsing settings to apply.

Return type: InlineDocument (class)

This function returns an inline syntax tree representing the parsed document.

Usage
Without custom settings
const html = parseInline(markup)
With custom settings
const html = parseInline(markup, {
  baseForUrlsStartingWithSlash: "https://example.com/en-us",
  keywords: { audio: "listen" }
})

render (function)

This function converts a syntax tree into HTML and returns the result.

Arguments
document: Document (class)

The syntax tree to convert into HTML.

renderingSettings (optional): Settings.Rendering (interface)

The custom rendering settings to apply.

Return type: string

This function returns HTML representing the rendered document.

Usage
Without custom settings
const html = render(document)
With custom settings
const html = render(document, {
  idPrefix: "article",
  terms: {
    footnoteReference: "footnote mention",
    reveal: "show"
  }
})

renderWithTableOfContents (function)

This function converts a syntax tree into two pieces of HTML, both of which are returned:

  1. A table of contents

  2. The document itself

Arguments
document: Document (class)

The syntax tree to convert into HTML.

renderingSettings (optional): Settings.Rendering (interface)

The custom rendering settings to apply.

Return type: DocumentAndTableOfContentsHtml (interface)

This function returns HTML representing the rendered document and table of contents.

Usage
Without custom settings
const { tableOfContentsHtml, documentHtml } =
  renderWithTableOfContents(document)
With custom settings
const { tableOfContentsHtml, documentHtml } =
  renderWithTableOfContents(document, {
    idPrefix: "article",
    terms: { revveal: "expand" }
  })

renderInline (function)

This function converts an inline syntax tree into inline HTML and returns the result.

To learn more about inline documents, see Inline documents.

Arguments
inlineDocument: InlineDocument (class)

The inline syntax tree to convert into HTML.

renderingSettings (optional): Settings.Rendering (interface)

The custom rendering settings to apply.

Return type: string

This function returns HTML representing the rendered inline document.

Usage
Without custom settings
const html = renderInline(inlineDocument)
With custom settings
const html = renderInline(inlineDocument, {
  idPrefix: "byline",
  terms: {
    footnoteReference: "footnote mention",
    reveal: "show"
  }
})

Up (class)

Anything you can accomplish using the Up class, you can accomplish using the regular Functions exported by the library.

However, the Up class can be helpful if you need to parse or render several documents sharing custom settings.

Those shared settings can be provided just once—in the constructor. Then, when calling methods on your object, you only need to provide settings that overwrite (or supplement) the ones you provided to the constructor.

const { Up } = require('up-lang')

const up = new Up(settings)
const html = up.parseAndRender(markup, changedSettings)

Constructor arguments

settings (optional): Settings (interface)

The custom parsing and/or rendering settings to apply to all subsequent method calls.

const up = new Up({
  parsing: {
    fancyEllipsis: "⋯",
    keywords: {
      audio: ["sound", "song"],
      revealable: "hide"
    }
  },
  rendering: {
    idPrefix: 'article',
    terms: { reveal: "expand" }
  }
})

Methods

This class's methods have the exact same names and arguments as the library's Functions.

Invoking a method with custom settings

When a method is invoked with custom settings, those settings are merged with the settings provided to the constructor. If any individual settings conflict, Up uses the conflicting values provided to the method.

Example
const up = new Up({
  parsing: {
    createSourceMap: true,
    fancyEllipsis: "⋯",
    keywords: {
      audio: ["sound", "song"],
      revealable: "hide"
    }
  },
  rendering: {
    terms: { reveal: "expand" }
  }
})

const html = up.parseAndRender(markup, {
  parsing: {
    createSourceMap: false,
    keywords: {
      audio: "listen"
    }
  },
  rendering: {
    idPrefix: "article"
  }
})
Result

In the above example, the following settings are ultimately applied:

{
  parsing: {
    createSourceMap: false,
    fancyEllipsis: "⋯",
    keywords: {
      audio: "listen",
      revealable: "hide"
    }
  },
  rendering: {
    idPrefix: "article",
    terms: { reveal: "expand" }
  }
}

Library configuration

The Up library works out of the box! No configuration is necessary.

However, all Functions do accept optional custom settings. These various settings are described below.

Settings (interface)

The Settings interface includes both parsing settings and rendering settings.

Use this interface to provide custom settings to functions that both parse markup and render the result to HTML:

Usage
const html = parseAndRender(markup, {
  parsing: {
    createSourceMap: true,
    keywords: { audio: "listen" }
  },
  rendering: {
    idPrefix: "article"
  }
})
Members (both of which are optional)
parsing: Settings.Parsing (interface)

The custom parsing settings to apply.

rendering: Settings.Rendering (interface)

The custom rendering settings to apply.

Settings.Parsing (interface)

The Settings.Parsing interface includes all parsing settings.

Use this interface to provide custom settings to functions that parse markup and return the resulting syntax tree:

As part of Settings (interface), this interface also provides parsing custom settings to functions that both parse markup and render the result to HTML:

Usage
const document = parse(markup, {
  createSourceMap: true,
  keywords: {
    audio: ["sound", "song"],
    audio: "listen"
  }
})
Members (all of which are optional)
createSourceMap (setting): boolean

Enables source mapping.

defaultUrlScheme (setting): string

The default URL scheme for URLs without one.

baseForUrlsStartingWithSlash (setting): string

The base for URLs starting with /.

baseForUrlsStartingWithHashMark (setting): string

The base for URLs starting with #.

fancyEllipsis (setting): string

Up replaces consecutive periods with this fancy ellipsis.

keywords (all of which are optional)

Customizing keywords

You can provide unlimited custom variations for each keyword. Custom keyword variations do not overwrite the default keywords.

const document = parse(markup, {
  keywords: {
    audio: ["sound", "song"],
    audio: "listen"
  }
})

Like the default keywords, custom keyword variations are case-insensitive.

audio: string or string[]

Recognized by Audio.

image: string or string[]

Recognized by Images.

revealable: string or string[]

Recognized by Inline revealables and Revealable blocks.

sectionLink: string or string[]

Recognized by Section links.

table: string or string[]

Recognized by Tables.

video: string or string[]

Recognized by Video.

createSourceMap (setting)

When createSourceMap is enabled, Up keeps track of the original line number for every instance of every outline writing convention.

This setting works by setting the sourceLineNumber field of each OutlineSyntaxNode (interface).

Usage
const html = parseAndRender(markup, {
  parsing: {
    createSourceMap: true
  }
})
Default value

false

Context

This setting belongs to Settings.Parsing (interface).

defaultUrlScheme (setting)

The defaultUrlScheme is prefixed to any link URL or media URL without a URL scheme.

For URLs with a URL scheme, this setting has no effect. Furthermore, this setting is not applied to URLs that start with / or #. For those URLs, see:

Usage
const html = parseAndRender(markup, {
  parsing: {
    defaultUrlScheme: "my-app://"
  }
})
Default value

"https://"

Context

This setting belongs to Settings.Parsing (interface).

baseForUrlsStartingWithSlash (setting)

The baseForUrlsStartingWithSlash is prefixed to any link URL or media URL starting with /.

Usage
const html = parseAndRender(markup, {
  parsing: {
    baseForUrlsStartingWithSlash: "https://example.com/blog/"
  }
})
Default value

"" (an empty string)

Context

This setting belongs to Settings.Parsing (interface).

baseForUrlsStartingWithHashMark (setting)

The baseForUrlsStartingWithSlash is prefixed to any link URL or media URL starting with #.

Usage
const html = parseAndRender(markup, {
  parsing: {
    baseForUrlsStartingWithHashMark: "https://example.com/blog/post/28"
  }
})
Default value

"" (an empty string)

Context

This setting belongs to Settings.Parsing (interface).

fancyEllipsis (setting)

Up automatically replaces consecutive periods with fancyEllipsis.

By default, fancyEllipsis is . If you want Up to use a different fancy ellipsis (e.g. or even . . .), set fancyEllipsis accordingly.

Usage
const html = parseAndRender(markup, {
  parsing: {
    fancyEllipsis: "⋯"
  }
})
Default value

"…"

Context

This setting belongs to Settings.Parsing (interface).

Settings.Rendering (interface)

The Settings.Rendering interface includes all rendering settings.

Use this interface to provide custom settings to functions that render syntax trees to HTML:

As part of Settings (interface), this interface also provides custom rendering settings to functions that both parse markup and render the result to HTML:

Usage
const html = render(document, {
  idPrefix: "article",
  terms: {
    footnoteReference: "footnote mention",
    reveal: "show"
  }
})
Members (all of which are optional)
idPrefix (setting): string

The prefix to apply to HTML IDs.

renderDangerousContent (setting): boolean

Enables the rendering of dangerous content. Enabling this setting is not recommended!

terms (all of which are optional)
footnote: string

Appears in the URLs of links pointing to footnotes in their footnote blocks.

footnoteReference: string

Appears in the URLs of links pointing back to footnote references (i.e. back to the superscripts within paragraphs).

hide: string

Appears on the button that hides revealable content.

reveal: string

Appears on the button that reveals revealable content.

sectionReferencedByTableOfContents: string

Appears in the URLs of table of contents entries.

You don't need to worry about escaping any characters in your custom terms! Up handles that for you.

idPrefix (setting)

If you are rendering multiple documents onto the same page, you need to use this setting to prevent HTML ID collisions between documents.

By default, idPrefix is up to prevent ID collisions with any HTML elements not rendered by Up. If you don't want any ID prefix, you can set idPrefix to an empty string.

You don't need to worry about escaping HTML for your idPrefix—Up automatically handles that for you. Furthermore, Up automatically converts any spaces in your idPrefix to hyphens.

Usage
const html = parseAndRender(markup, {
  rendering: {
    idPrefix: "article"
  }
})
Context

This setting belongs to Settings.Rendering (interface).

Default value

"up"

renderDangerousContent (setting)

Normally, Up will not render links or media elements with potentially exploitable URI schemes: javascript, vbscript, data, and file.

When this setting is enabled, Up will dutifully render all links and media elements.

Usage
const html = parseAndRender(markup, {
  rendering: {
    renderDangerousContent: true
  }
})
Default value

false

Context

This setting belongs to Settings.Rendering (interface).


Inline documents

In certain contexts, you might want to restrict a document to just a single line:

That's what inline documents are for! To take advantage of inline documents, use one of the following functions:

Syntax differences

Within inline documents, Up ignores all outline writing conventions. Furthermore, Footnotes and Section links aren't supported.

When Up encounters a footnote in an inline document, it pretends the author had used parentheses instead of a footnote.

Inline markup
My dad [^ Professor Oak] is very wise.
Output

My dad (Professor Oak) is very wise.

Within inline documents, Up doesn't recognize the syntax for section links. Consequently, their markup is instead treated as regular old text enclosed within brackets.

Inline markup
I enjoyed our conversation [topic: the weather].
Output

I enjoyed our conversation [topic: the weather].

Rendered HTML

When inline documents are rendered, the resulting HTML is not enclosed within any container element (e.g. <p>).

Inline markup
I *really* like Starcraft.
Rendered inline HTML
I <em>really</em> like Starcraft.

Abstract syntax tree classes

Unless you're fiddling with the abstract syntax tree of a parsed document, you can safely ignore this section.

Every class used in the abstract syntax tree is exported by the library.

const { Blockquote } = require("up-lang")

if (syntaxNode instanceof Blockquote) {
  // Do something
}

If you're using TypeScript, you can take advantage of several interfaces used in the abstract syntax tree, too.

const { SyntaxNode } = require("up-lang")

function handle(node: SyntaxNode): void {
  // Do something
}

All classes and interfaces are described below.

Document (class)

This class represents the syntax tree for a parsed document.

Extends

OutlineSyntaxNodeContainer (class)

Unique members
tableOfContents: Document.TableOfContents (class)

An object representing the document's table of contents.

create method (static)
Purpose

This method returns a ready-to-render syntax tree from a collection of outline syntax nodes.

Usually, you'll want to use this static method instead of the constructor.

Arguments
children: array of OutlineSyntaxNode (interface)

A collection of outline syntax nodes representing the content of this document.

Return type: Document (class)

This method creates and returns a ready-to-render Document object.

To prepare the document for rendering, this method:

  • Assigns footnotes their reference numbers

  • Extracts footnotes into footnote blocks

  • Produces a table of contents

  • Matches section links with table of contents entries

Constructor arguments
children: array of OutlineSyntaxNode (interface)

A collection of outline syntax nodes representing the content of this document.

tableOfContents (optional): Document.TableOfContents (class)

The document's table of contents.

Rendered HTML

When rendered to HTML, the document is not put into an outer container element.

<p>
  Unlike regular dental floss, you can use floss picks even if you're <em>not</em> a trained dental hygienist.
</p>
<p>
  Floss picks are sold in stylish, resealable plastic bags. You have no excuse not to buy some today.
</p>

Document.TableOfContents (class)

This class represents the table of contents for a document. The table of contents includes every heading except those found within Revealable content.

Members
entries: array of Document.TableOfContents.Entry (interface)

A collection of entries representing headings in the document. In fact, the objects in this collection are the same Heading (class) objects in the document itself.

Constructor arguments
entries: array of Document.TableOfContents.Entry (interface)

The entries in the table of contents.

Rendered HTML

Each entry in the table of contents renders a heading element corresponding to its level. This heading element contains a link to the appropriate section in the document.

To learn more on how headings are rendered, please see Heading (class).

<h1>
  <a href="#up-topic-1">Fun things</a>
</h1>
<h2>
  <a href="#up-topic-2">Games</a>
</h2>
<h3>
  <a href="#up-topic-3">Video games</a>
</h3>
<h4>
  <a href="#up-topic-4">Released in the 2000s</a>
</h4>
<h5>
  <a href="#up-topic-5">For Nintendo devices</a>
</h5>
<h6>
  <a href="#up-topic-6">Nintendo 64</a>
</h6>
<div aria-level="7" role="heading">
  <a href="#up-topic-6">Pokémon Puzzle League</a>
</div>
<h6>
  <a href="#up-topic-8">Game Boy</a>
</h6>
<div aria-level="7" role="heading">
  <a href="#up-topic-9">Game Boy Color Exclusives</a>
</div>
<div aria-level="8" role="heading">
  <a href="#up-topic-10">Warlocked</a>
</div>
Document.TableOfContents.Entry (interface)

This interface represents an entry in the table of contents.

Members
ordinalInTableOfContents: number

The entry's ordinal in the table of contents. The first ordinal is 1, not 0.

level: number

The heading level of the entry. Like HTML heading levels, a level of 1 is considered the most significant.

children: array of InlineSyntaxNode (interface)

The inline syntax nodes representing this entry in the table of contents.

titleMarkup: string

Currently, headings are the only writing convention that produce table of contents entries, so the titleMarkup field always represents the markup for the content line of a heading.

Section links compare their markupSnippetFromSectionTitle against this field.

sourceLineNumber: number

If createSourceMap (setting) is enabled, this field is set to the line number of the first line of markup that produced the heading represented by this entry. Source line numbers start at 1, not 0.

When rendered to HTML, entries with source line numbers are given a data-up-source-line attribute set the appropriate line number.

<h3 data-up-source-line="51">
  <a href="#up-topic-5">Video games</a>
</h3>
contentWithinTableOfContents method
Return type: array of InlineSyntaxNode (interface)

This method returns the inline syntax nodes that should represent this entry's content inside the table of contents itself.

Arguments

None.

InlineDocument (class)

This class represents the syntax tree for a parsed inline document.

Extends

InlineSyntaxNodeContainer (class)

Constructor arguments

See the constructor arguments for InlineSyntaxNodeContainer (class).

Rendered HTML

When rendered to HTML, an inline document is not put into an outer container element.

I <em>love</em> dental floss!

SyntaxNode (interface)

All syntax node classes must implement this interface.

Members
inlineDescendants method
Return type: array of InlineSyntaxNode (interface)

This method returns all inline descendants (including children, grandchildren, etc.).

Arguments

None.

Notes

This interface also has a render method, but it isn't relevant to developers using the Up library.

InlineSyntaxNode (interface)

All inline syntax node classes must implement this interface.

Extends

SyntaxNode (interface)

Unique members
searchableText method
Return type: string

This method returns the searchable text of the syntax node.

Ultimately, this method helps match Section links to the the most appropriate table of content entry.

Arguments

None.

textAppearingInline method
Return type: string

This method returns the text of the syntax node as it should appear inline. Some inline writing conventions don't have any text appearing inline, including Footnotes and Images.

This method is helps determine whether table cells are numeric.

Arguments

None.

OutlineSyntaxNode (interface)

All outline syntax node classes must implement this interface.

Extends

SyntaxNode (interface)

Unique members
sourceLineNumber: number

If createSourceMap (setting) is enabled, this field is set to the first line of markup that produced this syntax node. Source line numbers start at 1, not 0.

HTML elements rendered by outline syntax nodes with source line numbers are given a data-up-source-line attribute set the appropriate line number.

<p data-up-source-line="24">Hi there!</p>
descendantsToIncludeInTableOfContents method
Return type: array of Document.TableOfContents.Entry (interface)

This method returns any descendants (at any nesting level) to include in the table of contents.

Arguments

None.

RichInlineSyntaxNode (class)

This abstract class represents an inline syntax node that can contain other inline syntax nodes.

Extends

InlineSyntaxNodeContainer (class)

Implements

InlineSyntaxNode (interface)

Constructor arguments

See the constructor arguments for InlineSyntaxNodeContainer (class).

RichOutlineSyntaxNode (class)

This abstract class represents an outline syntax node that can contain other outline syntax nodes.

Extends

OutlineSyntaxNodeContainer (class)

Implements

OutlineSyntaxNode (interface)

Constructor arguments
children: array of OutlineSyntaxNode (interface)

A collection of outline syntax nodes representing the content of this syntax node.

options (optional)
sourceLineNumber: number

The line number of the first line of markup that created this syntax node.

InlineSyntaxNodeContainer (class)

This abstract class represents a container of inline syntax nodes.

Members
children: array of InlineSyntaxNode (interface)

A collection of inline syntax nodes representing the content of this container.

inlineDescendants method
Return type: array of InlineSyntaxNode (interface)

This method returns all inline descendants (including children, grandchildren, etc.).

Arguments

None.

Constructor arguments
children: array of InlineSyntaxNode (interface)

This field is described above.

OutlineSyntaxNodeContainer (class)

This abstract class represents a container of inline syntax nodes.

Members
children: array of InlineSyntaxNode (interface)

A collection of outline syntax nodes representing the content of this container.

descendantsToIncludeInTableOfContents method
Return type: array of Document.TableOfContents.Entry (interface)

This method returns any descendants (children, grandchildren, etc.) to include in the table of contents.

Arguments

None.

inlineDescendants method
Return type: array of InlineSyntaxNode (interface)

This method returns all inline descendants of children.

Arguments

None.

Constructor arguments
children: array of OutlineSyntaxNode (interface)

This field is described above.

MediaSyntaxNode (class)

All media syntax node classes extend this abstract class:

Implements
InlineSyntaxNode (interface)

Media conventions can appear inline (i.e. within paragraphs).

OutlineSyntaxNode (interface)

If a line consists solely of media conventions (or media conventions within links), those media conventions (or their outer links) are placed directly into the outline.

Unique members
description: string

The media's description.

url: string

Represents the media's URL after the following settings are applied:

Constructor arguments
description: string

The media's description.

url: string

The media's URL.

options (optional)
sourceLineNumber: number

The line number of the line of markup that created this media syntax node.

ParentheticalSyntaxNode (class)

This abstract class represents Parenthetical text. It exists solely to improve the expressiveness of the type system.

It is extended by both parenthetical syntax node classes:

Extends

RichInlineSyntaxNode (class)

Constructor arguments

See the constructor arguments for RichInlineSyntaxNode (class).

Audio (class)

Writing convention

Audio

Extends

MediaSyntaxNode (class)

Constructor arguments

See the constructor arguments for MediaSyntaxNode (class).

Rendered HTML
<audio controls src="https://a.clyp.it/ybct5hcl.mp3" title="Sadness theme from Infinity for Game Boy">
  <a href="https://a.clyp.it/ybct5hcl.mp3">Sadness theme from Infinity for Game Boy</a>
</audio>

Blockquote (class)

Writing convention

Blockquotes

Extends

RichOutlineSyntaxNode (class)

Constructor arguments

See the constructor arguments for RichOutlineSyntaxNode (class).

Rendered HTML
<blockquote>
  <p>Hi there!</p>
</blockquote>

Bold (class)

Writing convention

Audio

Extends

RichInlineSyntaxNode (class)

Constructor arguments

See the constructor arguments for RichInlineSyntaxNode (class).

Rendered HTML
<b>Hi there!</b>

BulletedList (class)

Writing convention

Bulleted lists

Implements

OutlineSyntaxNode (interface)

Unique members
items: array of BulletedList.Item (class)

The collection of items comprising this bulleted list.

Constructor arguments
items: array of BulletedList.Item (class)

This field is described above.

options (optional)
sourceLineNumber: number

The line number of the first line of markup that created this bulleted list.

Rendered HTML
<ul>
  <li>
    <p>Buy milk</p>
  </li>
  <li>
    <p>Buy bread</p>
  </li>
  <li>
    <p>Buy happiness</p>
  </li>
</ul>

BulletedList.Item (class)

This class represents an item in a bulleted list.

Extends

OutlineSyntaxNodeContainer (class)

Constructor arguments

See the constructor arguments for OutlineSyntaxNodeContainer (class).

CodeBlock (class)

Writing convention

Code blocks

Implements

OutlineSyntaxNode (interface)

Unique members
code: string

The code represented by this syntax node.

Constructor arguments
code: string

This field is described above.

options (optional)
sourceLineNumber: number

The line number of the first line of markup that created this code block.

Rendered HTML
<pre><code>const message = "Hi there!"</code></pre>

DescriptionList (class)

Writing convention

Description lists

Implements

OutlineSyntaxNode (interface)

Unique members
items: array of DescriptionList.Item (class)

The collection of items comprising this description list.

Constructor arguments
items: array of DescriptionList.Item (class)

This field is described above.

options (optional)
sourceLineNumber: number

The line number of the first line of markup that created this description list.

Rendered HTML
<dl>
  <dt>Kirby's Dreamland</dt>
  <dd>
    <p>A video game about a flying marshmallow.</p>
  </dd>
  <dt>Super Mario Land</dt>
  <dd>
    <p>A video game about a jumping plumber.</p>
  </dd>
</dl>

DescriptionList.Item (class)

This class represents a collection of subjects and their corresponding description.

Unique members
subjects: array of DescriptionList.Item.Subject (class)

The subjects described by description.

description: DescriptionList.Item.Description (class)

The description of subjects.

Constructor arguments
subjects: array of DescriptionList.Item.Subject (class)

This field is described above.

description: DescriptionList.Item.Description (class)

This field is described above.

DescriptionList.Item.Subject (class)

This class represents the collection of subjects described by a given description within a description list item.

Extends

InlineSyntaxNodeContainer (class)

Constructor arguments

See the constructor arguments for InlineSyntaxNodeContainer (class).

DescriptionList.Item.Description (class)

This class represents the description of a given collection of subjects within a description list item.

Extends

OutlineSyntaxNodeContainer (class)

Constructor arguments

See the constructor arguments for OutlineSyntaxNodeContainer (class).

Emphasis (class)

Writing convention

Emphasis

Extends

RichInlineSyntaxNode (class)

Constructor arguments

See the constructor arguments for RichInlineSyntaxNode (class).

Rendered HTML
<em>Hi there!</em>

ExampleUserInput (class)

Writing convention

Example user input

Implements

InlineSyntaxNode (interface)

Unique members
userInput: string

The example of user input.

Rendered HTML
<kbd>esc</kbd>

Footnote (class)

Writing convention

Footnotes

Extends

RichInlineSyntaxNode (class)

Unique members
referenceNumber: number

The number that appears in superscript for this footnote. Within a given document, this value must be unique.

Constructor arguments
children: array of InlineSyntaxNode (interface)

A collection of inline syntax nodes representing the content of this footnote.

options (optional)
referenceNumber: number

This field is described above.

Rendered HTML
<sup class="up-footnote-reference" id="up-footnote-reference-1">
  <a href="#up-footnote-1">1</a>
</sup>

FootnoteBlock (class)

Footnotes are written inline, but they aren't meant to appear inline in the final document. That would defeat the purpose of footnotes! Instead, footnotes are extracted and placed in footnote blocks. This class represents one of those footnote blocks.

Implements

OutlineSyntaxNode (interface)

Unique members
footnotes: array of Footnotes

The collection of footnotes comprising this footnote block.

Constructor arguments
footnotes: array of Footnotes

This field is described above.

Rendered HTML
<dl class="up-footnotes">
  <dt id="up-footnote-1">
    <a href="#up-footnote-reference-1">1</a>
  </dt>
  <dd>No relation to Warcraft!</dd>
  <dt id="up-footnote-2">
    <a href="#up-footnote-reference-2">2</a>
  </dt>
  <dd>The pathfinding algorithm had issues.</dd>
</dl>

Heading (class)

Writing convention

Headings

Extends

InlineSyntaxNodeContainer (class)

Implements
Document.TableOfContents.Entry (interface)

Headings are special! No other syntax node implements this interface.

OutlineSyntaxNode (interface)

But headings also serve as regular old outline syntax nodes.

Unique members
level: number

A heading's level represents its significance in the document. Like HTML heading levels, a level of 1 is considered the most significant.

Constructor arguments
children: array of InlineSyntaxNode (interface)

A collection of inline syntax nodes representing the content of this heading.

options
level: number

This field is described above.

titleMarkup: string

Represents the markup for the content line of this heading.

Section links compare their markupSnippetFromSectionTitle against this field.

ordinalInTableOfContents (optional): number

Represents this heading's ordinal in the table of contents. The first ordinal is 1, not 0.

sourceLineNumber (optional): number

The line number of the first line of markup that created this heading.

Rendered HTML
Levels 1–6

Headings with levels 1 through 6 render the appropriate heading element.

<h1>
  I am a level 1 heading!
</h1>

<h6>
  I am a level 6 heading!
</h6>
Levels 7 and higher

Headings with levels 7 and higher render <div role="heading"> elements with an aria-level attribute equal to their level.

<div aria-level="7" role="heading">
  I am a level 7 heading!
</div>

<div aria-level="10" role="heading">
  I am a level 10 heading!
</div>

Highlight (class)

Writing convention

Highlighting

Extends

RichInlineSyntaxNode (class)

Constructor arguments

See the constructor arguments for RichInlineSyntaxNode (class).

Rendered HTML
<mark>Hi there!</mark>

Image (class)

Writing convention

Images

Extends

MediaSyntaxNode (class)

Constructor arguments

See the constructor arguments for MediaSyntaxNode (class).

Rendered HTML
<img alt="Super Mario Land box art" src="https://i.imgur.com/TxlFlkX.jpg" title="Super Mario Land box art">

InlineCode (class)

Writing convention

Inline code

Implements

InlineSyntaxNode (interface)

Unique members
code: string

The inline code represented by this syntax node.

Constructor arguments
code: string

This field is described above.

Rendered HTML
<code class="up-inline-code">interface</code>

InlineQuote (class)

Writing convention

Inline quotes

Extends

RichInlineSyntaxNode (class)

Constructor arguments

See the constructor arguments for RichInlineSyntaxNode (class).

Rendered HTML
<q>I know!</q>

InlineRevealable (class)

Writing convention

Inline revealables

Extends

RichInlineSyntaxNode (class)

Constructor arguments

See the constructor arguments for RichInlineSyntaxNode (class).

Rendered HTML
<span class="up-revealable">
  <input checked class="up-hide" id="up-hide-button-1" name="up-revealable-1" type="radio">
  <label for="up-hide-button-1" role="button" tabindex="0">hide</label>
  <input class="up-reveal" id="up-reveal-button-1" name="up-revealable-1" type="radio">
  <label for="up-reveal-button-1" role="button" tabindex="0">reveal</label>
  <span role="alert">Ash fights Gary</span>
</span>

Italic (class)

Writing convention

Italics

Extends

RichInlineSyntaxNode (class)

Constructor arguments

See the constructor arguments for RichInlineSyntaxNode (class).

Rendered HTML
<i>I know!</i>

LineBlock (class)

Writing convention

Line blocks

Implements

OutlineSyntaxNode (interface)

Unique members
lines: array of LineBlock.Line (class)

The collection of lines comprising this line block.

Constructor arguments
lines: array of LineBlock.Line (class)

This field is described above.

options (optional)
sourceLineNumber: number

The line number of the first line of markup that created this syntax node.

Rendered HTML
<div class="up-lines">
  <div>Roses are red</div>
  <div>Violets are blue</div>
</div>

LineBlock.Line (class)

This class represents a line in a line block.

Extends

InlineSyntaxNodeContainer (class)

Constructor arguments

See the constructor arguments for InlineSyntaxNodeContainer (class).

Link (class)

Writing convention

Italics

Extends

RichInlineSyntaxNode (class)

Implements
OutlineSyntaxNode (interface)

If a line consists solely of media conventions (or media conventions within links), those media conventions (or their outer links) are placed directly into the outline.

Unique members
url: string

This links's URL after the following settings are applied:

Constructor arguments
children: array of InlineSyntaxNode (interface)

A collection of inline syntax nodes representing the content of this link.

url: string

This field is described above.

options
sourceLineNumber (optional): number

The line number of the line of markup that created this link.

Rendered HTML
<a href="https://example.com">Hi there!</a>

NormalParenthetical (class)

Writing convention

Parenthetical text produced by parentheses

Extends

ParentheticalSyntaxNode (class)

Constructor arguments

See the constructor arguments for ParentheticalSyntaxNode (class).

Rendered HTML
<small class="up-parenthetical">(Hi there!)</small>

NumberedList (class)

Writing convention

Numbered lists

Implements

OutlineSyntaxNode (interface)

Unique members
items: array of NumberedList.Item (class)

The collection of items comprising this numbered list.

start method
Return type: number

This method returns the starting ordinal of this list, if one was explicitly defined. Otherwise, this method returns undefined.

Arguments

None.

order method
Return type: NumberedList.Order (enum)

This method returns the order of this numered list.

Arguments

None.

Constructor arguments
items: array of NumberedList.Item (class)

This field is described above.

options (optional)
sourceLineNumber: number

The line number of the first line of markup that created this numbered list.

Rendered HTML
<ol reversed start="3">
  <li value="3">
    <p>Buy milk</p>
  </li>
  <li value="2">
    <p>Buy bread</p>
  </li>
  <li>
    <p>Buy happiness</p>
  </li>
</ol>

NumberedList.Item (class)

This class represents an item in a numbered list.

Extends

OutlineSyntaxNodeContainer (class)

Constructor arguments
children: array of OutlineSyntaxNode (interface)

A collection of outline syntax nodes representing the content of this list item.

options (optional)
ordinal: number

This field is described above.

NumberedList.Order (enum)

This enum represents the order of a numbered list. It has two members:

Paragraph (class)

Writing convention

Paragraphs

Extends

InlineSyntaxNodeContainer (class)

Implements

OutlineSyntaxNode (interface)

Constructor arguments
children: array of InlineSyntaxNode (interface)

A collection of inline syntax nodes representing the content of this paragraph.

options (optional)
sourceLineNumber: number

The line number of the line of markup that created this paragraph.

Rendered HTML
<p>Hi there!</p>

RevealableBlock (class)

Writing convention

Revealable blocks

Extends

RichOutlineSyntaxNode (class)

Constructor arguments

See the constructor arguments for RichOutlineSyntaxNode (class).

Rendered HTML
<div class="up-revealable">
  <input checked class="up-hide" id="up-hide-button-1" name="up-revealable-1" type="radio">
  <label for="up-hide-button-1" role="button" tabindex="0">hide</label>
  <input class="up-reveal" id="up-reveal-button-1" name="up-revealable-1" type="radio">
  <label for="up-reveal-button-1" role="button" tabindex="0">reveal</label>
  <div role="alert">
    <p>Ash fights Gary.</p>
  </div>
</div>

SectionLink (class)

Writing convention

Section links

Implements

InlineSyntaxNode (interface)

Unique members
markupSnippetFromSectionTitle: string

This field is compared against the titleMarkup field of every table of contents entry to find the most appropriate match.

Constructor arguments
markupSnippetFromSectionTitle: string

This field is described above.

entry: Document.TableOfContents.Entry (interface)

The table of contents entry (i.e. heading) this section link points to.

Rendered HTML
When matched with a heading

Up renders a link to that heading. The rendered link contains the heading's content.

<a href="#up-topic-77">Using the Up library</a>
When not matched with a heading

Up renders the value of markupSnippetFromSectionTitle in italics.

<i>Up library</i>

SquareParenthetical (class)

Writing convention

Parenthetical text produced by square brackets

Extends

ParentheticalSyntaxNode (class)

Constructor arguments

See the constructor arguments for ParentheticalSyntaxNode (class).

Rendered HTML
<small class="up-parenthetical up-square-brackets">[Hi there!]</small>

Stress (class)

Writing convention

Stress

Extends

RichInlineSyntaxNode (class)

Constructor arguments

See the constructor arguments for RichInlineSyntaxNode (class).

Rendered HTML
<strong>Hi there!</strong>

Table (class)

Writing convention

Tables

Implements

OutlineSyntaxNode (interface)

Unique members
header: Table.Header (class)

The header row.

rows: array of Table.Row (class)

The content rows.

caption: Table.Caption (class)

The optional caption.

Constructor arguments
header: Table.Header (class)

This field is described above.

rows: array of Table.Row (class)

This field is described above.

caption: Table.Caption (class)

This field is described above.

options (optional)
sourceLineNumber: number

The line number of the first line of markup that created this table.

Rendered HTML
Without header column
<table>
  <caption>Moves learned by the Pokémon Bulbasaur</caption>
  <tr>
    <th scope="col">Level</th>
    <th scope="col">Move</th>
    <th scope="col">Type</th>
    <th scope="col">Power</th>
    <th scope="col">Accuracy</th>
  </tr>
  <tr>
    <td class="up-numeric">1</td>
    <td>Tackle</td>
    <td>Normal</td>
    <td class="up-numeric">50</td>
    <td class="up-numeric">100%</td>
  </tr>
  <tr>
    <td class="up-numeric">3</td>
    <td>Growl</td>
    <td>Normal</td>
    <td></td>
    <td class="up-numeric">100%</td>
  </tr>
</table>
With header column
<table>
  <caption>Moves learned by the Pokémon Bulbasaur</caption>
  <tr>
    <th scope="col"></th>
    <th scope="col">Level</th>
    <th scope="col">Type</th>
    <th scope="col">Power</th>
    <th scope="col">Accuracy</th>
  </tr>
  <tr>
    <th scope="row">Tackle</th>
    <td class="up-numeric">1</td>
    <td>Normal</td>
    <td class="up-numeric">50</td>
    <td class="up-numeric">100%</td>
  </tr>
  <tr>
    <th scope="row">Growl</th>
    <td class="up-numeric">3</td>
    <td>Normal</td>
    <td></td>
    <td class="up-numeric">100%</td>
  </tr>
</table>

Table.Caption (class)

This class represents the caption of a table.

Extends

InlineSyntaxNodeContainer (class)

Constructor arguments

See the constructor arguments for InlineSyntaxNodeContainer (class).

Table.Cell (class)

This abstract class represents a table cell.

Extends

InlineSyntaxNodeContainer (class)

Unique members
isNumeric method
Return type: boolean

This method returns a boolean indicating whether the content of this cell is numeric.

Arguments

None.

Constructor arguments

See the constructor arguments for InlineSyntaxNodeContainer (class).

Table.Header (class)

This class represents the header row of a table.

Unique members
cells: array of Table.Header.Cell (class)

The cells in this header row.

Constructor arguments
cells: array of Table.Header.Cell (class)

This field is described above.

Table.Header.Cell (class)

This class represents a table header cell.

Extends

Table.Cell (class)

Constructor arguments

See the constructor arguments for InlineSyntaxNodeContainer (class).

Table.Row (class)

This class represents a content row in a table.

Unique members
cells: array of Table.Row.Cell (class)

The content cells in this row.

headerColumnCell: Table.Header.Cell (class)

The single header column cell for this row, if there is one.

Tables without header columns never have header column cells.

allCellsStartingWithHeaderColumnCell method
Return type: array of Table.Cell (class)

This method returns every cell in this row.

If the table has a header column, the row's headerColumnCell is the first item in the returned collection.

Arguments

None.

Constructor arguments
cells: array of Table.Row.Cell (class)

This field is described above.

headerColumnCell: Table.Header.Cell (class)

This field is described above.

Table.Row.Cell (class)

This class represents a regular (non-header) table cell.

Extends

Table.Cell (class)

Constructor arguments

See the constructor arguments for InlineSyntaxNodeContainer (class).

Text (class)

This class represents regular text content.

Implements

InlineSyntaxNode (interface)

Unique members
text: string

The text represented by this syntax node.

Constructor arguments
text: string

This field is described above.

Rendered HTML
Yes, 1 &lt; 2

ThematicBreak (class)

Writing convention

Thematic breaks

Extends

OutlineSyntaxNode (interface)

Constructor arguments
options (optional)
sourceLineNumber: number

The line number of the line of markup that created this thematic break.

Rendered HTML
<hr>

Video (class)

Writing convention

Video

Extends

MediaSyntaxNode (class)

Constructor arguments

See the constructor arguments for MediaSyntaxNode (class).

Rendered HTML
<video controls src="https://i.imgur.com/32fBpnh.mp4" title="Professor Leonard">
  <a href="https://i.imgur.com/32fBpnh.mp4">Professor Leonard</a>
</video>