Macros
A collection of compile-time macros for JSX. Macros are disabled by default and must be explicitly enabled by setting the macros option to true.
Setup
import { defineConfig } from 'vite'
import vueJsx from 'vue-jsx/vite'
export default defineConfig({
plugins: [
vueJsx({
macros: true,
}),
],
})The vue-jsx/volar plugin is optional. Use it only when you need editor or type-checking support for macro syntax, and keep its options consistent with the Vite configuration. See Volar Plugin for the setup.
Install as a standalone plugin
A standalone plugin is also available for use in Virtual DOM projects.
pnpm add @vue-jsx/macros -DConfiguration:
// vite.config.ts
import jsxMacros from '@vue-jsx/macros/vite'
export default {
plugins: [jsxMacros()],
}defineComponent | defineVaporComponent
defineComponent is used to define Virtual DOM components, while defineVaporComponent is used to define Vapor components.
Options
vueJsx({
defineComponent: {
/**
* @default ['defineComponent','defineVaporComponent']
*
* Set alias to an empty array to disable the defineComponent macro.
*/
alias: [],
},
})Features
- Supports the
awaitkeyword in async setup functions. - Automatically collects referenced props and adds them to the component's
propsoption.
import { , , , } from 'vue'
const = (
async (: {
?: string
?: string
// ^ Unreferenced props are treated as fallthrough attributes.
}) => {
await ()
const = ()
return () => (
<>
< {...}>{.}</>
</>
)
},
)
export default () => (
<>
< ="foo" ="bar" />
</>
)Compiled Code
import { defineComponent, useAttrs, withAsyncContext } from 'vue'
defineComponent(
async (props) => {
let __temp, __restore
;(([__temp, __restore] = withAsyncContext(() => nextTick())), await __temp, __restore())
const attrs = useAttrs()
return () => (
<div>
<span {...attrs}>{props.foo}</span>
</div>
)
},
{ props: { foo: null } },
)Props Handling
- Destructured props are automatically restructured to preserve reactivity.
- Append
!to a prop's default value to mark it as required. - Rest parameters in props are converted to
useAttrs(), andinheritAttrsdefaults tofalse.
import { } from 'vue'
const = (<,>({ = as , = ''!, ... }) => {
return (
<>
< {...}>{}</>
</>
)
})
export default () => <<string> foo={1} ="bar" />Compiled Code
import { defineVaporComponent } from 'vue'
import { createPropsDefaultProxy } from '/vue-macros/jsx-macros/with-defaults'
defineVaporComponent(
(_props) => {
const props = createPropsDefaultProxy(_props, { bar: '' })
const attrs = useAttrs()
return () => (
<div>
<span {...attrs}>{props.foo}</span>
</div>
)
},
{ props: { foo: null, bar: { required: true } }, inheritAttrs: false },
)defineModel
Limitations
- Hyphenated model names are not supported.
Features
- Append
!to mark the model as required. - Model values can be read synchronously after modification, without awaiting
nextTick(). Related issue
import { } from 'vue'
function () {
const = <string>()!
. = 'foo'
return <>{.}</>
}
export default () => {
const = ('')
return < ={.} />
}Compiled Code
import { ref } from 'vue'
import { useModel } from '/vue-macros/jsx-macros/use-model'
function Comp(_props: { modelValue: string; 'onUpdate:modelValue': (value: string) => any }) {
const modelValue = useModel<string>(_props, 'modelValue', { required: true })
modelValue.value = 'foo'
return <div>{modelValue.value}</div>
}defineSlots
Generic Slots
When using generics to define slots, all slots are treated as optional.
const = <{
: () => any
}>()
.?.()
// ^ optionalDefault Slot Values (Recommended)
Providing default implementations for slots is the recommended approach.
function <const >() {
const = ({
: (: { ?: }) => <>title slot: {.}</>,
: (: { : number }) => <>default slot: {.}</>,
})
return (
<>
<. />
<. ={1} />
</>
)
}
export default () => (
<<1>>
<template v-slot={{ }}>{}</template>
<template v-slot:={{ }}>{}</template>
</>
)defineExpose
Functions identically to defineExpose in Vue SFCs.
import { } from 'vue-jsx'
const = <,>({ = as }) => {
({
,
})
return < />
}
export default () => {
const = ()
.?.
return < ={} ={1 as } />
}Compiled Code
import { currentInstance } from 'vue'
import { useRef } from 'vue-jsx'
import { useExpose } from '/vue-macros/jsx-macros/use-expose'
const Comp = ({ foo }) => {
currentInstance.exposed = {
foo,
}
return <div />
}defineStyle
declare function defineStyle(style: string, options?: { scoped?: boolean }): voidFeatures
- Supports CSS variable and JavaScript variable binding.
- Multiple
defineStylecalls can be used within a single file. - Supports CSS preprocessors:
css,scss,sass,less,stylus,postcss.
defineStyle.scss(`...`)
defineStyle.stylus(`...`)
// ...Scoped Styles
- Top-level definitions default to
scoped: false. - Definitions within functions default to
scoped: true.
function ({ = 'red' }) {
.(`
.foo {
color: ${};
:deep(.bar) {
color: blue;
}
}
`)
return (
< ="red" ="foo bar">
foo
</>
)
}
(`
.bar {
background: black;
}
`)CSS Modules
Assigning defineStyle to a variable enables CSS Modules support.
export default () => {
const = .(`
.foo {
color: blue;
.bar {
background: red;
}
}
`)
return < ={.} />
}