FLIN escapes all HTML by default. When you write {user_input} in a template, FLIN converts <, >, &, ", and ' to their HTML entity equivalents. This prevents Cross-Site Scripting (XSS) attacks by ensuring that user input is never interpreted as HTML.
But sometimes you need to inject real HTML. A markdown renderer produces HTML that must be rendered as HTML, not as escaped text. An SVG icon is an HTML string that must be injected into the DOM. A WYSIWYG editor produces rich content that contains , , , and other tags that must be rendered correctly.
Session 258 added the tag -- FLIN's controlled escape hatch for injecting trusted HTML into the DOM.
The Problem: Escaped vs. Unescaped Output
// Default: HTML is escaped (safe)
content = "<b>Bold</b> and <i>italic</i>"
<div>{content}</div>
// Renders as: <b>Bold</b> and <i>italic</i>
// Displays as: <b>Bold</b> and <i>italic</i> (visible tags)// With
Without the tag, the content displays as literal text including the HTML tags. With the tag, the content is injected as real HTML and the browser renders it with formatting.
The Syntax
<raw>{expression}</raw>The tag wraps an expression whose value is a string of HTML. The string is injected directly into the DOM without escaping. The tag itself does not produce any DOM element -- it is a compiler directive that tells the renderer "trust this content."
// Markdown rendering
markdown_content = "# Hello\n\nThis is **bold** and *italic*."
html = render_markdown(markdown_content)
<article class="prose">
<raw>{html}</raw>
</article>// SVG icon injection
svg_path = '
// Rich text from WYSIWYG editor
Why "raw" and Not "html"
We considered naming the tag , following Svelte's {@html} directive. We chose instead for two reasons:
First, clarity of intent. communicates "this content is injected as-is, without any processing." It suggests that the developer is bypassing the safety system -- which is exactly what is happening. The name carries an appropriate level of caution.
Second, avoiding confusion with the element. In a .flin file that contains a full-page template, might be confused with the HTML document element. is unambiguous.
Security: The Developer's Responsibility
The tag is explicitly a security bypass. FLIN's default escaping prevents XSS attacks by ensuring that user input cannot contain executable HTML. The tag disables this protection for the wrapped expression.
The rule is simple: never use with user input.
// DANGEROUS: user input injected as HTML
user_comment = get_user_input()
<raw>{user_comment}</raw>
// If user_comment contains <script>alert('xss')</script>, it executes!// SAFE: sanitize before injecting
user_comment = get_user_input()
safe_comment = sanitize_html(user_comment)