STF (Structured Text Form) — No-HTML Module Authoring Guide # STF (Structured Text Form) — No-HTML Module Authoring Guide > A plain, linear text format for writing course module content without HTML — no tags to type, no block editor, screen-reader-first by design. --- ## Overview STF lets you write a module's content as plain text field-by-field instead of an HTML fragment. You type a field name in CAPS followed by a colon, then the text for that field. The **Modular Course Builder & Packager** (`packager.php`) automatically recognizes STF text pasted or typed into a module's Content box and compiles it to HTML before packaging — you never write a tag. ``` TITLE: Coaching Basics BODY: Coaching is a **collaborative process** between coach and learner. SECTION: HEADING: Active Listening BODY: Active listening means giving your ==full attention== to the speaker. OBJECTIVE: Recognize the four components of active listening. ``` No indentation is required, and section numbers (`SECTION 1:`, `SECTION 2:`) are read for your own reference only — the parser doesn't check them, so getting a number "wrong" or leaving it off entirely can't break anything. --- ## When to use STF vs. raw HTML STF currently covers **plain text content only**: titles, headings, paragraphs, and simple labeled/bulleted fields. It does **not** yet have a way to represent the interactive `sl-*` web components (`<sl-flipcard>`, `<sl-accordion>`, `<sl-hotspot-container>`, `<sl-quiz>`, and the rest) — that mapping is planned but not built yet. **STF and raw HTML cannot currently be mixed in the same module.** Each module's Content box is either STF or HTML, not both — if a module needs any interactive component, keep it (or convert it) as a raw HTML fragment rather than STF. If you start converting an HTML module to STF by hand (for example, replacing `<h1>Title</h1>` with `TITLE: Title`) and leave other real HTML tags further down in the same box, those leftover tags will be treated as literal text and escaped, not parsed — they'll show up on the page as visible `<p>` or `<sl-flipcard>` text rather than being rendered. The tool will warn you when this happens, but the safest approach is to convert a module fully to one format or the other, not partway. Each module card has a **Content Format** dropdown (Auto-detect / Force Raw HTML / Force STF) next to the Module Title and Filename fields. Auto-detect is the default and works for the common case, but if you're not sure which format the tool picked, or a mixed-content warning appears, use this dropdown to say explicitly which one you mean. --- ## Fields Four field names get special treatment: | Field | Where | Renders as | | :--- | :--- | :--- | | `TITLE:` | Once, at the top of the module (before any `SECTION:`) | `<h1>` — the module's main heading | | `HEADING:` | Inside a `SECTION:`, or at the top level | `<h2>` | | `BODY:` / `DESCRIPTION:` | Anywhere | One or more `<p>` paragraphs | | `SECTION:` | Starts a new subsection | Wraps the fields that follow in their own `<section>` until the next `SECTION:` | Any other field name works too — there's no fixed list to memorize. A field used once renders as a labeled line (e.g. `OBJECTIVE: Recognize the pattern` → **Objective:** Recognize the pattern). The same field name repeated more than once renders as a bulleted list instead: ``` OBJECTIVE: Recognize active listening OBJECTIVE: Practice open questions ``` A field's value is everything up to the next `FIELD:` or `SECTION:` line — you can write multiple lines under one field, and a blank line starts a new paragraph within a `BODY:`/`DESCRIPTION:` field. --- ## Inline Formatting Three inline markers are supported inside any field's text: | Type | Marker | Renders as | | :--- | :--- | :--- | | Bold | `**text**` | `<strong>text</strong>` | | Italic | `*text*` | `<em>text</em>` | | Highlight | `==text==` | `<mark>text</mark>` | These three specific symbols were chosen after testing against NVDA at its default "Some" punctuation verbosity level — `*` and `==` are read aloud ("star", "equals equals"), while brackets, braces, and backticks are silent at that level and were dropped rather than shipped broken for screen reader authors. This has only been verified on NVDA; if you use JAWS or VoiceOver and notice different behavior, that's worth reporting. To include a literal asterisk or equals sign instead of triggering formatting, put a backslash in front of it: `\*` or `\=`. --- ## Full Example ``` TITLE: Screen Readers as Interpreters BODY: A screen reader doesn't just read text aloud — it **interprets** the page's structure for you, the same way a human interpreter conveys meaning, not just words. SECTION: HEADING: Why Structure Matters BODY: Without proper headings and labels, a screen reader has ==nothing to interpret== beyond a flat wall of text. OBJECTIVE: Explain why semantic HTML matters to screen reader users OBJECTIVE: Identify at least two structural elements screen readers rely on SECTION: HEADING: Wrap Up BODY: Structure is *not* optional — it's the whole interpretation. ``` Compiles to: ```html <section> <h1>Screen Readers as Interpreters</h1> <p>A screen reader doesn't just read text aloud — it <strong>interprets</strong> the page's structure for you, the same way a human interpreter conveys meaning, not just words.</p> <section> <h2>Why Structure Matters</h2> <p>Without proper headings and labels, a screen reader has <mark>nothing to interpret</mark> beyond a flat wall of text.</p> <ul> <li>Explain why semantic HTML matters to screen reader users</li> <li>Identify at least two structural elements screen readers rely on</li> </ul> </section> <section> <h2>Wrap Up</h2> <p>Structure is <em>not</em> optional — it's the whole interpretation.</p> </section> </section> ```