JSX Basics
TriFrost includes a fast, runtime-aware JSX rendering engine designed specifically for SSR use cases.
Unlike traditional React-based setups, TriFrost JSX compiles directly to HTML strings, with built-in support for contextual rendering, scoped styles, secure script hydration, and per-request nonce injection.
This document covers the basics of using JSX with TriFrost, from setup to rendering, and introduces the primitives available to all JSX files.
π For more advanced usage, see:
Configuration
To use JSX in TriFrost, your tsconfig.json
must be set up to use @trifrost/core
as the JSX factory:
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "@trifrost/core",
...
}
}
Make sure the jsxImportSource is set to @trifrost/core
, which exports the appropriate JSX primitives (jsx
, jsxs
, Fragment
) to compile JSX syntax into the TriFrost runtime-compatible shape.
π§ How it works
TriFrost uses a custom JSX runtime that translates JSX into a lightweight virtual element tree. This tree is processed by the ctx.html(...)
method, which ultimately produces an HTML string for the response.
Example usage:
export const handler = async ctx => {
return ctx.html(
<html>
<head>
<title>My App</title>
</head>
<body>
<h1>Hello, world!</h1>
</body>
</html>
);
};
Behind the scenes, ctx.html()
:
- Activates a rendering context (styles, script registry, etc.)
- Converts JSX into an HTML string via
render(...)
- Injects collected styles and scripts
- Applies nonce where needed
- Resets the rendering context
𧬠Context Awareness
TriFrost's JSX engine can access the active request context via utilities that are available through the createScript
factory.
// script.ts
const {Script, script} = createScript({ atomic: true });
From the above script
object we can get:
script.env(key)
: Access environment variables from the currently rendering context'sctx.env
in a typesafe wayscript.state(key)
: Access route state (eg: path parameters, state set by middleware, ...) from the currently rendering context'sctx.state
script.nonce()
: Access the CSP nonce for script/style tags
Example:
import {script} from './script';
export function Meta() {
return <meta name="env" content={script.env('NODE_ENV')} />;
}
These helpers ensure JSX output is aware of the current request lifecycle without having to pass ctx around everywhere.
π Learn more about:
πΌ Components
Any function that returns JSX can be used as a component:
function Button() {
return <button>Click Me</button>;
}
function Page() {
return <main><Button /></main>;
}
The compiler calls each function component during rendering, injecting any props
you've passed.
π§© Primitives
TriFrost includes two first-class JSX components:
<Script>
This lets you write inline scripts in JSX:
<Script>{el => {
el.innerText = 'JS loaded';
}}</Script>
Scripts are de-duplicated, scoped, and automatically get the correct nonce.
If you pass a src
, it will render a remote script:
<Script src="https://example.com/foo.js" />
π Learn more in JSX Script Behavior
<Style>
Used to inject collected styles from the createCss()
system:
<Style />
Itβs typically used once in <head>
and auto-replaced with all used CSS.
π‘ Tip: Note that when doing component-based renders (SSC) in combination with full-page renders (SSR) you might want to include
<Style />
in those components as well, this ensures the styles native to that component get served as well if that component is rendered standalone. Only the first<Style />
instance gets injected (the one inhead
for example), all the rest get ignored safely unless they are the first one for that render.
π Learn how to craft responsive masterpieces and more in JSX Style System
π Styling with createCss
TriFrost ships with an atomic, scoped, and SSR-safe CSS Engine:
const css = createCss();
const box = css({
padding: '1rem',
color: 'black',
':hover': { color: 'blue' },
});
<div className={box}>Hover me</div>
Out of the box this gives you:
- Nesting (like in sass)
- Ergonomic access to pseudo selectors like
:hover
,:focus
, etc. - Built-in media queries, exposed via
css.media
, for usage at a component level, etc. - Built-in theming and variable tokens via
css.var
andcss.theme
- Built-in reuse tokens via
definitions
π Learn how to craft responsive masterpieces and more in JSX Style System
π€ Rendering Pipeline Summary
When calling ctx.html(...)
with JSX:
- The internal
rootRender(...)
activates rendering engines (script, style, ...) and sets the current ctx as the active context - JSX is walked and rendered to HTML
- Styles (
<Style>
) and Scripts (<Script>
) get collected, deduped, and injected. Important to note that only the used bits get injected - CSP nonces are applied if present
- Final HTML string is returned
TLDR
- Configure TypeScript with
jsx: react-jsx
andjsxImportSource: @trifrost/core
- Use
ctx.html(...)
to render JSX trees - Use
env()
,state()
, andnonce()
for request-aware rendering <Script>
and<Style>
auto-handle nonce, deduping, and hydrationcreateCss()
enables scoped, atomic styles without a client-side runtime
Next Steps
For deeper JSX capabilities and understanding, explore: