Use Typst within Astro
npm install astro-typstastro-typstimport / include / read files or resources
.typ
![]()
with src= emitted SVG assets (#20)
fontArgs in config)
bash
npm install astro-typst
or
pnpm add astro-typst
or
yarn add astro-typst
`
The latest stable version (0.12) needs the following beta versions of typst.ts:
> [!IMPORTANT]
> You must install the following peer dependencies to select a typst version.
`json
"dependencies": {
...
"@myriaddreamin/typst-ts-node-compiler": ">=0.6.1-rc2",
"@myriaddreamin/typst-ts-renderer": ">=0.6.1-rc2",
"@myriaddreamin/typst.ts": ">=0.6.1-rc2",
...
}
`
To use typst v0.13, please install @0.6.1-rc5 and later release candidates:
`json
"@myriaddreamin/typst-ts-node-compiler": "^0.6.1-rc5",
"@myriaddreamin/typst-ts-renderer": "^0.6.1-rc5",
"@myriaddreamin/typst.ts": "0.6.1-rc5",
`
To use typst v0.14, you need to install later typst.ts versions, respectively:
!NPM Version
`json
"@myriaddreamin/typst-ts-node-compiler": "^0.7.0-rc2",
"@myriaddreamin/typst-ts-renderer": "^0.7.0-rc2",
"@myriaddreamin/typst.ts": "0.7.0-rc2",
`
Usage
Checkout the live demo!
$3
`js
// astro.config.mjs
import { typst } from 'astro-typst';
... // other imports
export default defineConfig({
integrations: [
/* other integrations /...,
typst({
options: {
remPx: 14,
},
target: (id: string) => {
console.debug(Detecting ${id});
if (id.endsWith('.html.typ') || id.includes('/html/'))
return "html";
return "svg";
},
// === Use html-text output rather than hAST ===
// htmlMode: "text", // added in v0.12.3
// ===
instead of inlined `
The target function determines which mode a file will render in. The default is:
`
*.html.typ => html export
*.svg.typ => svg export
/html/ => html export
/svg/ => svg export
`
Then you can use .typ files just like anything else in Astro: render directly by router, or import in another file.
Example:
`mdx
import Paper from "./_test.typ";
`
Force HTML output:
`mdx
import Paper from "./_test.typ?html";
`
Force SVG output:
`mdx
import Paper from "./_test.typ?svg";
`
You can also emit SVG to standalone files on build mode. Modify the emitSvg and emitSvgDir option in the config. (Added in v0.10)
$3
To use the component, you need to manually install a dependency to avoid SSR errors:
`
npm install @myriaddreamin/typst-ts-node-compiler
or
pnpm add @myriaddreamin/typst-ts-node-compiler
or
yarn add @myriaddreamin/typst-ts-node-compiler
`
and add this to your /astro.config.(t|j)s/:
`diff
export default defineConfig({
...,
vite: {
ssr: {
- external: [...],
+ external: [..., "@myriaddreamin/typst-ts-node-compiler"],
},
...,
},
...,
});
`
Then, you can pass either one of code | src | input to the component:
`astro
---
import { Typst } from "astro-typst/src/components";
const code =
;
---
`
$3
See demo.
#### Frontmatter
> metadata exposes a value to the query system without producing visible content.
Attach a label frontmatter to the metadata declaration:
`typ
#let desc = [$oo$ fun with math]
#metadata(
(
title: "Test page",
author: "Neko",
desc: desc,
date: datetime(
year: 2024,
month: 8,
day: 7,
),
)
)
`
yields
`json
{
"title": "Test page",
"author": "Neko",
"desc": {
"children": [
{
"block": false,
"body": {
"func": "text",
"text": "∞"
},
"func": "equation"
},
{ "func": "space" },
{ "func": "text", "text": "fun with" },
{ "func": "space" },
{
"block": false,
"func": "raw",
"text": "math"
}
],
"func": "sequence"
},
"date": "datetime(year: 2024, month: 8, day: 7)"
}
`
This is only a demo for how various typst types will be converted;
you don't need to use all of them.
$3
Import Jump.astro, or add the following snippet to your page
Snippet
`js
/**
Copyright 2025 Myriad-Dreamin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
function findAncestor(el, cls) {
while ((el = el.parentElement) && !el.classList.contains(cls));
return el;
}
window.handleTypstLocation = function (elem, page, x, y) {
const docRoot = findAncestor(elem, 'typst-doc');
const children = docRoot.children;
let nthPage = 0;
for (let i = 0; i < children.length; i++) {
if (children[i].tagName === 'g') {
nthPage++;
}
if (nthPage == page) {
const page = children[i];
const dataWidth = page.getAttribute('data-page-width');
const dataHeight = page.getAttribute('data-page-height');
const rect = page.getBoundingClientRect();
const xOffsetInner = Math.max(0, x / dataWidth - 0.05) * rect.width;
const yOffsetInner = Math.max(0, y / dataHeight - 0.05) * rect.height;
const xOffsetInnerFix = (x / dataWidth) * rect.width - xOffsetInner;
const yOffsetInnerFix = (y / dataHeight) * rect.height - yOffsetInner;
const docRoot = document.body || document.firstElementChild;
const basePos = docRoot.getBoundingClientRect();
const xOffset = rect.left - basePos.left + xOffsetInner;
const yOffset = rect.top - basePos.top + yOffsetInner;
const left = xOffset + xOffsetInnerFix;
const top = yOffset + yOffsetInnerFix;
console.log('scrolling to', xOffset, yOffset, left, top);
window.scrollTo(xOffset, yOffset);
return;
}
}
};
`
Development
$3
`bash
pnpm tsc -w
in another terminal
pnpm dev
`
$3
`bash
pnpm compile
``