Summary#
Some things an app shows are documents in their own right — a rendered mail above all, with its own <html>, its
own <body> and every style inline. Dropped into the page they would restyle it and be restyled by it. Frame
shows such a document beside everything else, looking exactly as it will look where it is going:
var mail = OrderConfirmation(order); // an [Email] template's RenderedEmail
Frame(mail.Html, title: "Preview of the order confirmation", h: 720);Signature#
Frame(string html, title: string, <style props>) // w / h / borderW / border / rounded … size and frame ithtml is the document itself — not an address. title names the frame for a screen reader, which announces it as a
region of its own; always give one.
Description#
It is sandboxed, whatever the document says#
Every Frame carries an empty sandbox and referrerpolicy="no-referrer", on the server's first paint and in the
browser alike. So the document it shows:
- runs no script — a
<script>inside it is inert; - has an origin of its own — it cannot read the app's cookies or storage, or reach the page around it;
- submits no form, opens no window and navigates nothing outside itself;
- sends no referrer — a picture it loads does not learn which page of the app showed it.
There is no setting to relax any of that. It is what makes it safe to show HTML that carries data somebody typed — a customer's name in a mail — inside a page a member of staff is signed in to.
Size it#
A frame is as wide as its container and 320 pixels tall until told otherwise. Give it the height the document needs
with h: — a mail preview reads well at 700–900 — and a border with borderW: / border: / rounded:, like any
box.
Examples#
A mail, previewed on a staff page#
entity Order {
[MaxLength(40)] string Reference;
security { allow read when IsAuthenticated; }
}
[Email]
component Confirmation(Order order) {
subject => $"Your order {order.Reference}";
render {
Box(bg: "#F6F7F9", p: 6) {
Text($"Thank you — order {order.Reference} is reserved for you.", fontSize: 20, fontWeight: 700);
}
}
}
string PreviewHtml(Guid orderId) {
var order = Order.Single(o => o.Id == orderId);
return Confirmation(order).Html;
}
[Route("/preview/{id}")]
[Title("Preview")]
component PreviewPage(Guid id) {
string html = "";
on mount { html = PreviewHtml(id); }
render {
Stack(gap: 3, p: 6) {
Text("What the customer gets", fontWeight: 600);
if (html != "") { Frame(html, title: "Preview of the order confirmation", h: 720, borderW: 1, rounded: 8); }
}
}
}See also#
- [Email] — mail rendered from data — the
[Email]templates whose rendered HTML a frame previews. - The EmailTemplates kit — mail that looks designed — the parts a designed mail is built from.
- Markdown — rendering markdown text — formatted text that belongs IN the page, rather than a document beside it.