@outloud/adonis-jsx
v1.0.0
Published
JSX template support in AdonisJS 6/7.
Downloads
45
Readme
AdonisJS JSX
JSX support for AdonisJS 6/7.
Features
- Render React JSX components to HTML on the server.
- Share global and request-scoped state with templates.
- Integrates with AdonisJS Mail for email templating.
- Support for custom render functions (e.g., jsx-email, react-email).
- Type-safe configuration and template props.
Getting Started
Install the package from the npm registry and configure it.
node ace add @outloud/adonis-jsxThen add "jsx": "react-jsx" to your tsconfig.json compiler options.
// tsconfig.json
{
"compilerOptions": {
"jsx": "react-jsx"
}
}See config/jsx.ts for available configuration options.
Usage
Rendering views
Use the jsx property on the HTTP context to render JSX templates in your controllers.
import type { HttpContext } from '@adonisjs/core/http'
export default class TestController {
index({ jsx }: HttpContext) {
return jsx.render(() => import('#views/index'), { name: 'Adonis' })
}
}Define your view as a default-exported React component.
// resources/views/index.tsx
interface Props {
name: string
}
export default function Index(props: Props) {
return (
<div>Hello {props.name}!</div>
)
}Global state
You can share global state with all templates using the JsxEngine service. The app and config globals are automatically injected by the provider.
// providers/app.provider.ts
import type { ApplicationService } from '@adonisjs/core/types'
import type { I18n } from '@adonisjs/i18n'
export default class AppProvider {
constructor(protected app: ApplicationService) {}
async boot() {
const i18n = await this.app.container.make('i18n')
const jsx = await this.app.container.make('jsx')
jsx.global('i18n', i18n.locale(i18n.defaultLocale))
jsx.global('brandName', 'Acme')
}
}
declare module '@outloud/adonis-jsx' {
export interface GlobalState {
i18n: I18n
brandName: string
}
}
Access global state in your templates using the GlobalContext or HttpContext context.
import { useContext } from 'react'
import { HttpContext } from '@outloud/adonis-jsx'
export default function Header() {
// if you are rendering the template from a controller,
// you can also use HttpContext to access request-scoped state
const { brandName } = useContext(HttpContext)
return <h1>{brandName}</h1>
}Usage outside of controllers
You can also use the JsxEngine service to render templates outside of controllers, such as in scheduled tasks or event listeners.
import jsx from '@outloud/adonis-jsx/service'
const html = await jsx.render(() => import('#views/email'), { name: 'John' })Mail integration
[!NOTE] This requires @adonisjs/mail package (v10.2.0+) to be installed and configured.
The package automatically integrates with AdonisJS Mail when detected. Use htmlView() on the message to render a JSX email template.
import mail from '@adonisjs/mail/services/main'
await mail.send((message) => {
message
.to('[email protected]')
.subject('Reset Password')
.htmlView(() => import('#emails/password'), {
name: 'John',
link: 'https://example.com/reset',
})
})Define your email template as a React component.
// resources/emails/password.tsx
import { useContext } from 'react'
import { GlobalContext } from '@outloud/adonis-jsx'
interface Props {
name: string
link: string
}
export default function Password(props: Props) {
const { brandName } = useContext(GlobalContext)
return (
<>
<h1>{brandName}</h1>
<p>Hi {props.name},</p>
<a href={props.link}>Reset Password</a>
</>
)
}react-email support
Install the @react-email/render package and configure a custom render function.
// config/jsx.ts
import { render } from '@react-email/render'
import { defineConfig } from '@outloud/adonis-jsx'
const jsxConfig = defineConfig({
mail: {
render: (template) => render(template),
}
})jsx-email support
Using jsx-email requires an extra step: create a custom context and pass it to the JSX engine configuration.
// resources/emails/contexts/email.context.ts
import type { GlobalState } from '@outloud/adonis-jsx'
import { createContext } from 'jsx-email'
export const EmailContext = createContext<GlobalState>({} as GlobalState)// config/jsx.ts
import { render } from 'jsx-email'
import { defineConfig } from '@outloud/adonis-jsx'
import { EmailContext } from '#emails/contexts/email.context'
const jsxConfig = defineConfig({
mail: {
context: EmailContext,
render: (template) => render(template, { inlineCss: true }),
}
})