A component in a snippet
Put the component insnippets/ as a .jsx file with a named export:
snippets/counter.jsx
blog/launch.mdx
A component inside a post
For a component you only need once, export it right in the.mdx file:
blog/launch.mdx
Rules
- React hooks without imports:
useState,useEffect,useRef,useCallback,useMemo,useContext,useReducer,useId,useLayoutEffect,useTransitionanduseDeferredValueare available without importing them, and in a.jsxsnippet you can import anything else from"react". - Use named exports. Notra doesn’t support
export defaultorexport *. - Import only from your repository. Paths start with
/(from the site root),./or../, and Notra doesn’t support npm packages, JSON files or dynamicimport(). A.jsxsnippet can only import from"react", so import every snippet you need in the MDX file. - No Node.js.
process,require,Buffer,eval,new Functionandimport.metastop the build. - Tailwind classes work. This includes the theme colors
bg-background,text-foreground,text-muted-foreground,border-border,bg-primaryandtext-primary, and you can also style class names from any.cssfile.
Browser-only code
Components render once during the build and again in the browser, so code that readswindow, document or localStorage while rendering breaks the build. Read them in useEffect:
snippets/local-time.jsx
client:only="react":
client:visible (when it scrolls into view) or client:idle (when the browser is idle).
Reusable content
MDX files insnippets/ hold text you repeat across posts, and you import them as a component and pass props to fill in the blanks:
snippets/install.mdx
blog/launch.mdx
{{ product }} only work in posts rather than snippets, so pass a prop instead.
Your own buttons
Give your component class names and style them in any.css file:
snippets/button.jsx
buttons.css
Security
Builds run in a sandbox without network access, but Notra serves your components from your domain, so anyone who can commit to the repository can run JavaScript onacme.com/blog. Only give write access to people you trust with your website.