Pages and text
Most of a web page is text, and HTML has an element for every kind of text: a heading, a paragraph, a quotation, a piece of code, a date. In Salam you write them with plain readable names and the compiler turns them into the HTML tags. This lesson shows each one with an example you can run.
The shape of a page
A page: block holds everything on the page. Before the first element you can set things that belong to the page itself: title is the text on the browser tab, lang and dir say which language and which direction the text has, and background, color and the other style properties at that level paint the whole page. Everything else is an element. An element opens with its name and a colon and closes with end, and what goes between is attributes and child elements, written as name = value with no commas.
The text of an element is its content attribute. It is always plain text: a < or an & in it is shown as it is and never becomes markup, so text that comes from a user can never break the page. Put several words in one string, or build a string with + from constants and numbers.
page:
title = "A short article"
global: selector = "body" font family = "system-ui, sans-serif" max width = "34rem" margin = "2rem auto" line height = 1.6 end
heading group:
h1: content = "Why we write pages in Salam" end
paragraph:
content = "Published "
time: datetime = "2026-10-26" content = "26 October 2026" end
end
end
paragraph: content = "A page is a tree of elements. Each element has a name, some attributes and sometimes children." end
heading: size = 2 content = "One language" end
paragraph: content = "The page and the program that serves it are written in the same language, so a name that is wrong is found while compiling." end
line: end
small: content = "Written for the Salam course." end
endThe preview above is the real page the compiler built. The global line is a style rule for the whole page, and you will meet it again in the CSS lessons; here it only gives the page a readable font and a comfortable width.
Headings
Headings give a page its outline. heading takes a size from 1 to 6, and h1 to h6 are the same thing under their HTML names. Use a single level 1 for the title of the page and then go down one level at a time: a level 3 belongs under a level 2, not directly under a level 1. Browsers draw the levels in decreasing sizes, but choose the level for its meaning and change the size with CSS. When a heading has a subtitle, wrap both in a heading group as the example above does.
Paragraphs, breaks and rules
paragraph is a block of text, and browsers leave space above and below it. Inside a paragraph, break starts a new line, which is right for an address or a poem and wrong as a way to add space, because empty space is a job for CSS. line draws a horizontal rule between two topics, and word break marks where a long word may be cut if it does not fit.
A paragraph can hold child elements next to its own content. The content text always comes first, and the children follow in the order you write them. So a sentence with a bold word in the middle is written as the first part in content, then the bold element, then a span with the rest. The span is a neutral container: it adds no meaning and no look of its own, which makes it the element for styling a few words.
Emphasis and inline text
Inline elements live inside a line of text. Several of them look alike in the browser and differ in meaning, and the meaning is what screen readers and search engines use. strong is important text and bold is only bold type. emphasis is stress, the word you say louder, and italic is a different voice, such as a foreign word. mark highlights what is relevant right now, strikethrough shows what is no longer true, and small is for small print. subscript and superscript raise and lower text for formulas. code, keyboard, sample and variable are the four ways to write about computers.
page:
title = "Inline text"
global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" line height = 1.7 end
paragraph:
content = "Water is H"
subscript: content = "2" end
span: content = "O and energy is E = mc" end
superscript: content = "2" end
span: content = ". " end
strong: content = "Do not" end
span: content = " drink the " end
emphasis: content = "second" end
span: content = " glass. Press " end
keyboard: content = "Ctrl + S" end
span: content = " to save, or call " end
code: content = "save()" end
span: content = " from your code. " end
mark: content = "This part is highlighted." end
end
endPick the element for what the text is, not for how it looks. Looks change in CSS in one place, but the meaning stays with the text, and a reader that cannot see your page, such as a screen reader, depends on it.
Quotations, code and preformatted text
quote is a short quotation inside a sentence and browsers add the quotation marks. block quote is a longer quotation set apart from the text. Both can take a cite attribute with the address of the source, and cite as an element names a work such as a book or a film. For a listing where every space and line break matters, use preformatted: it shows its text in a monospace font and keeps the layout exactly. Write a line break inside the string as \n.
page:
title = "Quotes and code"
global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
block quote:
cite = "https://example.com/essay"
content = "Everything should be made as simple as possible, but no simpler."
end
paragraph:
content = "From "
cite: content = "an essay on design" end
span: content = ", as she put it: " end
quote: content = "start small" end
span: content = "." end
end
preformatted:
content = "func main:\n println \"Hello\"\nend"
background = "#f3f4f6"
padding = "12px"
border radius = "8px"
end
endEdits, dates and abbreviations
deleted and inserted show what was taken out and what was put in, and both accept a datetime and a cite. time holds a date or a time in words for people and in a fixed format in its datetime for programs, and data does the same for any other value. An abbreviation keeps its full form in title, and definition marks the word that a sentence defines.
page:
title = "Edits and abbreviations"
global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" line height = 1.7 end
paragraph:
content = "The meeting moved from "
deleted: datetime = "2026-10-26" content = "Monday" end
span: content = " to " end
inserted: datetime = "2026-10-26" content = "Tuesday" end
span: content = "." end
end
paragraph:
definition: content = "Salam" end
span: content = " is written in " end
abbreviation: title = "Cascading Style Sheets" content = "CSS" end
span: content = " and " end
abbreviation: title = "HyperText Markup Language" content = "HTML" end
span: content = " for you." end
end
paragraph:
content = "Price: "
strikethrough: content = "$20" end
span: content = " " end
data: value = "15" content = "$15" end
end
endMixed directions and ruby
A page in English often contains a Persian name, and a Persian page often contains an English one. Browsers decide the order of such text by a standard algorithm that usually works, but a name at the edge of a sentence can still pull the punctuation to the wrong side. Wrap a piece of text of unknown direction in isolate and it is laid out on its own, without affecting its neighbours. direction override is the blunt tool: it forces one direction whatever the characters say. ruby places a small annotation, usually a pronunciation, above the base text.
page:
title = "Mixed directions"
global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" line height = 1.8 end
paragraph:
content = "Comment from "
isolate: content = "محمد" end
span: content = " and from " end
isolate: content = "Sara" end
span: content = "." end
end
paragraph:
content = "Forced: "
direction override: dir = "rtl" content = "abc 123" end
end
paragraph:
ruby:
content = "東京"
ruby text: content = "Tōkyō" end
end
end
endReference: every text element
Each element below is shown with a short example. Wherever an element has attributes of its own they are listed under it, and the attributes that every element has are in the lesson on the head and global attributes. The examples are checked by the compiler, so you can paste any of them inside a page: block. Persian names work in any file, and the Persian lessons use them.
heading (Persian: سرتیتر; HTML: <h1>)
A heading. The size attribute chooses the level, from 1 (the largest and most important) to 6. Search engines and screen readers build the outline of your page from its headings, so use one level 1 per page and do not skip levels.
heading: size = 2 content = "Our story" end
| Attribute | What it does | Example |
|---|---|---|
sizeاندازه | The heading level as a whole number from 1 to 6. Without it the heading is level 1, and a number outside the range is cut to the nearest level, so 7 gives a level 6. [int] | heading: size = 3 content = "Opening hours" end |
h1 (HTML: <h1>)
A level 1 heading written with its HTML name. heading with size = 1 produces exactly the same tag.
h1: content = "Welcome" end
h2 (HTML: <h2>)
A level 2 heading, used for the main sections under the page title.
h2: content = "Features" end
h3 (HTML: <h3>)
A level 3 heading, used for subsections of a level 2 section.
h3: content = "Speed" end
h4 (HTML: <h4>)
A level 4 heading.
h4: content = "Benchmarks" end
h5 (HTML: <h5>)
A level 5 heading.
h5: content = "Method" end
h6 (HTML: <h6>)
A level 6 heading, the smallest of the six.
h6: content = "Footnote" end
heading group (Persian: گروه سرتیتر; HTML: <hgroup>)
Groups a heading with its subtitle or tagline so they count as one heading in the outline.
heading group:
h1: content = "Salam" end
paragraph: content = "A language for the web and beyond" end
end
paragraph (Persian: پاراگراف; HTML: <p>)
A paragraph of text. It is the element you will use most. Browsers put space above and below it.
paragraph: content = "Salam compiles to fast native code." end
span (Persian: تکه; HTML: <span>)
A neutral inline container with no meaning of its own. Use it to style or script a few words inside a line of text.
paragraph:
content = "The total is "
span: content = "42" color = "crimson" end
end
break (Persian: شکست; HTML: <br>)
A line break inside a paragraph. It is a void element, so it takes no content. Use it for poems and addresses, not to add vertical space.
paragraph:
content = "First line"
break: end
span: content = "Second line" end
end
line (Persian: خط; HTML: <hr>)
A thematic break, drawn as a horizontal rule. It marks a change of topic between paragraphs.
line: end
word break (Persian: شکست واژه; HTML: <wbr>)
Marks a place where the browser may break a very long word if it needs to. It is invisible otherwise.
paragraph:
content = "super"
word break: end
span: content = "cali" end
word break: end
span: content = "fragilistic" end
end
bold (Persian: پررنگ; HTML: <b>)
Draws attention to text with bold type without saying it is important, such as a product name in a review.
paragraph:
content = "Try the "
bold: content = "Pro" end
span: content = " plan." end
end
strong (Persian: قوی; HTML: <strong>)
Text of strong importance. Browsers show it in bold and screen readers may stress it.
paragraph:
strong: content = "Warning:" end
span: content = " this cannot be undone." end
end
italic (Persian: کج; HTML: <i>)
Text set apart from its surroundings in tone or voice, such as a technical term or a thought. Browsers show it in italics.
paragraph:
content = "The word "
italic: content = "salam" end
span: content = " means peace." end
end
emphasis (Persian: تاکید; HTML: <em>)
Stress emphasis, the word you would say louder. Browsers show it in italics and screen readers stress it.
paragraph:
content = "I said "
emphasis: content = "never" end
span: content = "." end
end
underline (Persian: زیرخط; HTML: <u>)
Text with an unarticulated annotation, such as a misspelling mark. Do not use it for links, because readers expect underlined text to be clickable.
paragraph:
content = "Check the "
underline: content = "speling" end
span: content = " here." end
end
strikethrough (Persian: خط خورده; HTML: <s>)
Text that is no longer accurate or relevant, drawn with a line through it, such as an old price.
paragraph:
strikethrough: content = "$20" end
span: content = " $15 today" end
end
small (Persian: ریز; HTML: <small>)
Side comments and small print, such as copyright lines and legal notes. Browsers show it one size smaller.
small: content = "Prices include VAT." end
mark (Persian: برجسته; HTML: <mark>)
Highlights text because it is relevant right now, like a search match. Browsers paint it with a yellow background.
paragraph:
content = "Results for "
mark: content = "salam" end
span: content = ": 12 pages" end
end
subscript (Persian: زیرنویس; HTML: <sub>)
Text set lower than the line, as in chemical formulas.
paragraph:
content = "H"
subscript: content = "2" end
span: content = "O" end
end
superscript (Persian: بالانویس; HTML: <sup>)
Text set higher than the line, as in exponents and footnote marks.
paragraph:
content = "E = mc"
superscript: content = "2" end
end
code (Persian: کد; HTML: <code>)
A short piece of computer code inside text. Browsers use a monospace font.
paragraph:
content = "Call "
code: content = "println" end
span: content = " to print." end
end
keyboard (Persian: صفحه کلید; HTML: <kbd>)
Text the user types, usually a key or a shortcut.
paragraph:
content = "Press "
keyboard: content = "Ctrl + S" end
span: content = " to save." end
end
sample (Persian: نمونه خروجی; HTML: <samp>)
Sample output from a program, shown in a monospace font.
paragraph:
content = "The program printed "
sample: content = "Hello, World" end
end
variable (Persian: متغیر; HTML: <var>)
The name of a variable in a formula or in programming text. Browsers show it in italics.
paragraph:
content = "The area is "
variable: content = "w" end
span: content = " times " end
variable: content = "h" end
end
abbreviation (Persian: کوتهنوشت; HTML: <abbr>)
An abbreviation or acronym. Put the full form in title so it shows when the pointer rests on it.
abbreviation: title = "HyperText Markup Language" content = "HTML" end
definition (Persian: تعریف; HTML: <dfn>)
The term being defined in a sentence that defines it.
paragraph:
definition: content = "Salam" end
span: content = " is a compiled language with a built in page language." end
end
cite (Persian: نام اثر; HTML: <cite>)
The title of a creative work, such as a book, a film or a paper. It is not for the name of a person.
paragraph:
content = "I loved "
cite: content = "The Little Prince" end
span: content = "." end
end
quote (Persian: نقل قول; HTML: <q>)
A short quotation that stays inside a paragraph. Browsers put quotation marks around it.
paragraph:
content = "She said "
quote: content = "see you soon" end
span: content = " and left." end
end
| Attribute | What it does | Example |
|---|---|---|
citeمنبع نقل | The address of the page the quotation comes from. It is not shown, but tools can read it. [url] | quote: cite = "https://example.com/talk" content = "less is more" end |
block quote (Persian: نقل قول بلند; HTML: <blockquote>)
A longer quotation set apart from the text around it, usually indented.
block quote:
content = "Simplicity is the ultimate sophistication."
end
| Attribute | What it does | Example |
|---|---|---|
citeمنبع نقل | The address of the source of the quotation. [url] | block quote: cite = "https://example.com/essay" content = "Make it simple." end |
preformatted (Persian: پیشقالب; HTML: <pre>)
Text that keeps its spaces and line breaks exactly, shown in a monospace font. It is the right choice for code listings and ASCII art.
preformatted: content = "line one\n line two" end
time (Persian: زمان; HTML: <time>)
A date or a time. The readable text can be anything, and datetime gives the exact value for programs.
time: datetime = "2026-10-26" content = "26 October 2026" end
| Attribute | What it does | Example |
|---|---|---|
datetimeزمان دقیق | The machine readable date or time, such as 2026-10-26 or 2026-10-26T09:30. [datetime] | time: datetime = "2026-10-26T09:30" content = "9:30 in the morning" end |
data (Persian: داده; HTML: <data>)
Links readable text to a value a program can use, such as a product number. value is required.
data: value = "4021" content = "Green tea" end
| Attribute | What it does | Example |
|---|---|---|
valueمقدار | The machine readable value. It is required. [string] | data: value = "7" content = "seven" end |
deleted (Persian: حذف شده; HTML: <del>)
Text that was removed from a document. Browsers draw it with a line through it.
paragraph:
content = "Meet at "
deleted: content = "5 pm" end
inserted: content = "6 pm" end
end
| Attribute | What it does | Example |
|---|---|---|
citeمنبع نقل | The address of a page that explains why the text was removed. [url] | deleted: cite = "https://example.com/changes" content = "old text" end |
datetimeزمان دقیق | When the text was removed, as a date or a date and time. [datetime] | deleted: datetime = "2026-10-26" content = "old text" end |
inserted (Persian: افزوده; HTML: <ins>)
Text that was added to a document. Browsers underline it.
inserted: content = "New in this version" end
| Attribute | What it does | Example |
|---|---|---|
citeمنبع نقل | The address of a page that explains why the text was added. [url] | inserted: cite = "https://example.com/changes" content = "new text" end |
datetimeزمان دقیق | When the text was added, as a date or a date and time. [datetime] | inserted: datetime = "2026-10-26T09:30" content = "new text" end |
ruby (Persian: آوانما; HTML: <ruby>)
Annotation for East Asian and other scripts, a small pronunciation guide shown above or beside the base text. It holds the base text plus ruby text elements.
ruby:
content = "漢"
ruby text: content = "han" end
end
ruby text (Persian: متن آوانما; HTML: <rt>)
The small annotation text of a ruby.
ruby:
content = "東京"
ruby text: content = "Tōkyō" end
end
ruby parenthesis (Persian: پرانتز آوانما; HTML: <rp>)
Parentheses shown only by browsers that cannot draw ruby, so the annotation still reads as 漢(han).
ruby:
content = "漢"
ruby parenthesis: content = "(" end
ruby text: content = "han" end
ruby parenthesis: content = ")" end
end
isolate (Persian: جداساز جهت; HTML: <bdi>)
Isolates a piece of text from the direction of the text around it. It is the safe way to put a name of unknown direction, such as a user name, inside a sentence.
paragraph:
content = "User "
isolate: content = "محمد" end
span: content = " left a comment." end
end
direction override (Persian: جهت اجباری; HTML: <bdo>)
Forces the direction of its text, ignoring what the characters say. dir is required.
direction override: dir = "rtl" content = "abc 123" end
Try it yourself
- Write a recipe page with a level 1 title, an ordered list of steps and a
timefor the cooking time. - Take the article above and add a
block quotewith aciteand amarkon the sentence you want people to notice. - Change a
strongto aboldand aboldto astrong. Does the page look different? What would a screen reader do?