o:

The o: global attribute exports an element as a file. Its content is served at /name.ext in the playground output, and at https://<route>/name.ext on RTEdge.net once you deploy.

Syntax

html
<script o:=nav.js>…</script>
<style o:=.css>…</style>
<template o:=About.html>…</template>
<img hidden alt o:=logo.png src="data:image/png;base64,…">

Value

name

The file name. It must contain a . and must not contain a /. Names that start with a dot, such as .css, .js, .md and .svg, are valid and common. Stick to letters, digits, _ and - plus one .. An empty value is not a file name.

Description

o: makes the content of the element a static file. The colon is attribute syntax only: the URL is /nav.js, not /:nav.js.

EnvironmentWhere the file is served
Playground/name on the output origin.
RTEdge.nethttps://<route>/name for every route in Code.D. For example, with Code.D = ['new'], <script o:=nav.js> is served at https://new.rt.ht/nav.js as text/javascript.

Other attributes refine the export:

o:type

Sets the content type.

o:content

Chooses the property that becomes the body.

h:*

Adds response headers.

worker:fs

Also hands the content to the worker as an env.FS asset.

The playground and RTEdge.net share the same tables and defaults. They differ in the places listed under Usage notes. For the full story, see Exporting files.

Usage notes

Names

Names that start with a dot are served at <route>/.js and so on. A dotless name is never served in the playground, and on RTEdge.net a path without a dot is redirected to its slash form, so a dotless name is unreachable in practice. Matching is case-sensitive on RTEdge.net, and a query string is ignored, so nav.js?v=2 serves nav.js.

The playground resolves each name as a URL, so names with /, spaces or non-ASCII characters work there. RTEdge.net never serves a name with /, and a file exists only directly under its route path: /route/sub/x.js belongs to the route route/sub. Names with spaces or non-ASCII characters do not match, because the request path is percent-encoded and the stored name is not. Names that contain :, ? or #, and names that end in *, are not reachable either, and a few names are reserved by the platform: see Reserved paths.

Default bodies

The body depends on the element. The playground, RTEdge.net and File Sync use the same table:

ElementDefault body
<script>, <style>textContent
<template>innerHTML
<img> without o:content whose src starts with data:The decoded bytes (a binary file)
Every other element, including <img> with another srcouterHTML

Bodies are taken verbatim: nothing is trimmed, so the textContent of a script includes the line break after the start tag. Use o:content to export another property.

Elements that share a name

Elements with the same name are joined in document order, with one line break between the parts. The file keeps the type and headers of the first element; the o:type and h:* of later elements are silently ignored. Any duplicate that involves a binary part is an error, so never reuse the name of a binary export.

Binary files

An <img> with a data: URL and no o:content exports the decoded bytes. The payload is base64 when a parameter of the URL equals base64, and percent-decoded otherwise. Only data: URLs export bytes: an <img> with another src exports its own outerHTML. Hide the carrier image with hidden and an empty alt.

Pages and templates

A <template> is the usual way to export a page, because its default body is innerHTML. The playground does not look inside templates, so o: on an element nested in a template is ignored there, while RTEdge.net exports it too. Keep shared exports, such as a stylesheet, outside templates. See Building a multi-page site.

Worker scripts

o: on a <script type=worker> exports the script in the playground but not on RTEdge.net, because RTEdge.net removes every worker script before it extracts files. worker:fs on a worker script works in both.

Freshness in the playground

The playground rebuilds exports only when the output reloads in full. Exports from JavaScript-type scripts are always fresh. Exports from <style>, <template>, data blocks, <img> and other elements go stale after an edit until Load (F5), unless the output reloads on every edit because of sync=reload or a <script reload>. See Live sync and reloads.

Access and redaction

A deployed file is a public URL unless edge:user protects it. edge:redact or edge:remove on the exporting element hides the element from the served page, but the file is still produced and served.

What deploy does to the body

Deploy strips o: from the served HTML and from export bodies, together with o:type, o:content and the other prefixed attributes. The deployed source keeps them. The playground reads bodies from the parsed element before any cleanup, so outerHTML and innerHTML bodies keep RTCode attributes and nested edge:remove and edge:redact content. RTEdge.net reads them from a cleaned copy: RTCode attributes are stripped, nested edge:remove becomes blank lines and nested edge:redact becomes a comment, and the result is re-serialized. Those bodies are therefore not byte-identical between the two. Script and style textContent and binary exports are. RTEdge.net also keeps CR and CRLF line endings from the source, where the playground normalizes them to LF.

File Sync

With File Sync on, Agent Folder Share writes each element that has o: as a file named by its value, with the authored source as content. See Exporting files.

CodeLens

Each o:= start tag shows 📄 ./<name>, followed by → 🌐 //<first route>/<name> when the playground has routes. An invalid name shows ⚠️ with the hint must contain . or must not contain /.

Examples

Exporting a module

html
<script type=module o:=greet.js>
  export const greet = name => `Hello, ${name}!`
</script>
<output id=out></output>
<script type=module>
  import { greet } from './greet.js'
  out.value = greet('o:')
</script>

The first script runs in the page and is also served as /greet.js. Edit it and the output reloads, which rebuilds the file.

Exporting data

html
<script type=application/json o:=data.json>{"version":1}</script>
<iframe src=data.json></iframe>

Script types that are not JavaScript never run, so the script is a container for data. .json is served as application/json. After you edit the script, press Load (F5) to rebuild the file.

Exporting an image

html
<img hidden alt o:=dot.png src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=">
<img src=dot.png alt=dot width=64 height=64>

The data: URL is decoded to 68 bytes and served as image/png.

Specifications

Not part of any specification. o: is an RTCode.io and RTEdge.net feature.

It builds on these standards:

Specification
HTML Standard: Syntax
HTML Standard: The template element
Service Workers
RFC 9110: HTTP Semantics
RFC 2397: The "data" URL scheme

Availability

FeaturePlaygroundRTEdge.netNotes
o: exportsYesYesThe same extension table and defaults.
Names with /, spaces or non-ASCII charactersYesNoServed only by the playground.
o: inside a <template>NoYesThe template itself can be exported in both.
o: on <script type=worker>YesNoWorkers are removed before files are extracted.
Bodies from outerHTML and innerHTMLAs authoredCleanedRTEdge.net strips RTCode attributes and re-serializes.
File Sync (Agent Folder Share)YesNoChrome or Edge on desktop.

See also