Top SitesVue Macros

Machine Readiness

Stored receipt and evidence

Overall

27

Readable

90

Callable

0

Commerce

0

Payment

0

Machine Access

Inspect the site's MCP endpoint

Open MCP explorer

DialtoneApp can scan the stored discovery files for this domain, try the MCP initialize handshake, and show the raw protocol transcript.

Purchase boundary

read only

Control boundary

unknown

Payment rails

None

Payment providers

None

Payment methods

None

Payment protocols

None

Payment assets

None

Payment networks

None

Capabilities

None

Verified payment surface

No

Crypto only

No

Readable docs

llms, llms-full

Products

0

Variants

0

Priced variants

0

Currencies

0

Offers

0

Priced offers

0

Priced actions

0

Samples

Offer samples

No stored offer samples.

Samples

Action samples

No stored action samples.

Samples

Product samples

No stored product samples.

Document

robots.txt

Not stored for this site.

Document

llms.txt

Open llms.txt
# Vue Macros

> Modern Way to Writing Vue App

Explore more macros and syntax sugar to Vue.

## Table of Contents

- [ ESLint Integration ](/guide/eslint-integration.md)
- [ Nuxt Integration ](/guide/nuxt-integration.md)
- [Astro Integration ](/guide/astro-integration.md)
- [betterDefine ](/features/better-define.md)
- [booleanProp ](/features/boolean-prop.md)
- [Bundler Integration ](/guide/bundler-integration.md)
- [chainCall ](/macros/chain-call.md)
- [Configurations](/guide/configurations.md)
- [defineEmit ](/macros/define-emit.md)
- [defineGeneric ](/volar/define-generic.md)
- [defineModels ](/macros/define-models.md)
- [defineOptions ](/macros/define-options.md)
- [defineProp ](/macros/define-prop.md)
- [defineProps ](/macros/define-props.md)
- [definePropsRefs ](/macros/define-props-refs.md)
- [defineRender ](/macros/define-render.md)
- [defineSlots ](/macros/define-slots.md)
- [defineStyleX ](/macros/define-stylex.md)
- [exportExpose ](/features/export-expose.md)
- [exportProps ](/features/export-props.md)
- [exportRender ](/features/export-render.md)
- [Getting Started](/guide/getting-started.md)
- [hoistStatic ](/features/hoist-static.md)
- [jsxDirective ](/features/jsx-directive.md)
- [jsxRef ](/volar/jsx-ref.md)
- [Migration from v2 to v3](/guide/migration-v3.md)
- [namedTemplate ](/features/named-template.md)
- [Reactivity Transform ](/features/reactivity-transform.md)
- [scriptLang ](/features/script-lang.md)
- [scriptSFC ](/volar/script-sfc.md)
- [setupComponent ](/macros/setup-component.md)
- [setupJsdoc ](/volar/setup-jsdoc.md)
- [setupSFC ](/macros/setup-sfc.md)
- [shortBind ](/features/short-bind.md)
- [shortEmits ](/macros/short-emits.md)
- [shortVmodel ](/macros/short-vmodel.md)
- [templateRef ](/volar/template-ref.md)
- [Usage](/macros.md)

Document

llms-full.txt

Open llms-full.txt
---
url: /guide/eslint-integration.md
---
#  ESLint Integration 

## Installation

::: code-group

```bash [pnpm]
pnpm add -D @vue-macros/eslint-config
```

```bash [yarn]
yarn add -D @vue-macros/eslint-config
```

```bash [npm]
npm i -D @vue-macros/eslint-config
```

:::

## Configuration

### Flat Configuration

```js [eslint.config.js]
import vueMacros from '@vue-macros/eslint-config/flat'
export default [
  vueMacros,
  // ...your other configurations
]
```

### Legacy Configuration

```jsonc [.eslintrc]
{
  "extends": [
    "@vue-macros/eslint-config",
    // ...your other configurations
  ],
}
```

---

---
url: /guide/nuxt-integration.md
---
#  Nuxt Integration 

### Installation

::: code-group

```bash [npm]
npm i -D @vue-macros/nuxt
```

```bash [yarn]
yarn add -D @vue-macros/nuxt
```

```bash [pnpm]
pnpm add -D @vue-macros/nuxt
```

:::

## Configuration

```ts [nuxt.config.ts]
export default {
  modules: [
    '@vue-macros/nuxt',
    // ...
  ],
  macros: {
    // overrides config options
  },
}
```

***

:tada: Congratulations! That's all.

To learn more about the macros, please visit [All Macros](/macros/) :laughing:.

---

---
url: /guide/astro-integration.md
---
# Astro Integration 

### Installation

::: code-group

```bash [npm]
npm i -D @vue-macros/astro
```

```bash [yarn]
yarn add -D @vue-macros/astro
```

```bash [pnpm]
pnpm add -D @vue-macros/astro
```

:::

## Configuration

```ts [astro.config.mjs]
import Vue from '@astrojs/vue'
import Macros from '@vue-macros/astro'
import { defineConfig } from 'astro/config'

export default defineConfig({
  integrations: [
    Vue(),
    Macros({
      // overrides config options
    }),
  ],
})
```

## TypeScript Support & Volar Support

See the corresponding chapter on [Bundler Integration](./bundler-integration.md#typescript-support)

***

:tada: Congratulations! That's all.

To learn more about the macros, please visit [All Macros](/macros/) :laughing:.

---

---
url: /features/better-define.md
---
# betterDefine 

With enabling `betterDefine`, imported types are supported in `<script setup>` type-based-macros.

[Related issue](https://github.com/vuejs/core/issues/4294)

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Nuxt 3   | :white\_check\_mark: |
|   Vue 2    | :white\_check\_mark: |
| TypeScript | :white\_check\_mark: |

## Basic Usage

::: code-group

```vue twoslash [App.vue]
<script setup lang="ts">
// #region basic
type BaseProps = {
  title: string
}

export type { BaseProps }
// #endregion basic
// ---cut---
// @noErrors
import type { BaseProps } from './types'

interface Props extends BaseProps {
  foo: string
}
const props = defineProps<Props>()
</script>
```

<<< ./better-define.md#basic{ts} \[types.ts]

:::

## ⚠️ Limitations

### Complex types

Complex types are not supported in some key places. For example:

#### What are Complex Types?

* All utility types
  * [Built-in types](https://www.typescriptlang.org/docs/handbook/utility-types.html)
  * All types from `type-fest` package.
  * `typeof` keyword.
  * ...
* Index Signature
  ```ts
  interface Type {
    [key: string]: string
  }
  ```
* Generics will be ignored directly

#### What are Key Places?

* The names of props.

```ts
// ✅
defineProps<{
  foo: ComplexType
}>()

// ❌
defineProps<{
  [ComplexType]: string
}>()
```

* The names of emits.

```ts
interface Emits {
  (event: 'something', value: ComplexType): void // ✅
  (event: ComplexType): void // ❌
}
```

---

---
url: /features/boolean-prop.md
---
# booleanProp&#x20;

Convert `<Comp checked />` to `<Comp :checked="true" />`.

Convert `<Comp !checked />` to `<Comp :checked="false" />`.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     |        :x:         |
| Volar Plugin | :white\_check\_mark: |

## Options

```ts
interface Options {
  /**
   * @default '!'
   */
  negativePrefix?: string
}
```

## Usage

```vue twoslash
<script setup>
import type { FunctionalComponent } from 'vue'

export const Comp: FunctionalComponent<
  {
    checked: true,
    enabled: false,
  },
> = () => null
// ---cut---
// @noErrors
import Comp from './Comp.vue'
</script>

<template>
  <Comp checked !enabled />
  //             ^?
</template>
```

```vue twoslash
<script setup lang="ts">
// Comp.vue
defineProps<{
  checked: true
  enabled: false
}>()
</script>
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "booleanProp": true,
    },
  },
}
```

---

---
url: /guide/bundler-integration.md
---
# Bundler Integration&#x20;

## Installation

::: tip

Vite and Rollup are fully supported, while other bundlers have limited support.

:::

::: code-group

```bash [npm]
npm i -D vue-macros
```

```bash [yarn]
yarn add -D vue-macros
```

```bash [pnpm]
pnpm add -D vue-macros
```

:::

::: code-group

```ts [Vite]
// vite.config.ts
import Vue from '@vitejs/plugin-vue'
import VueMacros from 'vue-macros/vite'
// import VueJsx from '@vitejs/plugin-vue-jsx'
// import VueRouter from 'unplugin-vue-router/vite'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue(),
        // vueJsx: VueJsx(), // if needed
        // vueRouter: VueRouter({ // if needed
        //   extensions: ['.vue', '.setup.tsx']
        // })
      },
      // overrides plugin options
    }),
  ],
})
```

```ts [Rollup]
// rollup.config.js (Requires Rollup 3+)
import Vue from 'unplugin-vue/rollup'
import VueMacros from 'vue-macros/rollup'
// import VueRouter from 'unplugin-vue-router/rollup'

export default {
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue(),
        // vueJsx: VueJsx(), // if needed
        // vueRouter: VueRouter({ // if needed
        //   extensions: ['.vue', '.setup.tsx']
        // })
      },
      // overrides plugin options
    }),
  ],
}
```

```js [esbuild]
// esbuild.config.js
import { build } from 'esbuild'
// import VueRouter from 'unplugin-vue-router/esbuild'

build({
  plugins: [
    require('vue-macros/esbuild')({
      plugins: {
        vue: require('unplugin-vue/esbuild')(),
        // vueJsx: VueJsx(), // if needed
        // vueRouter: VueRouter({ // if needed
        //   extensions: ['.vue', '.setup.tsx']
        // })
      },
      // overrides plugin options
    }),
  ],
})
```

```js [Webpack]
// webpack.config.js (Requires Webpack 5+)
module.exports = {
  /* ... */
  plugins: [
    require('vue-macros/webpack')({
      // overrides plugin options
    }),
  ],
}
```

```js [Rspack]
// rspack.config.js
module.exports = {
  /* ... */
  plugins: [
    require('vue-macros/rspack')({
      // overrides plugin options
    }),
  ],
}
```

```js [Rsbuild]
// rsbuild.config.js
module.exports = {
  // ...
  tools: {
    rspack: {
      plugins: [
        require('vue-macros/rspack')({
          // overrides plugin options
        }),
      ],
    },
  },
}
```

```js [Vue CLI]
// vue.config.js (Requires Vue CLI 5+)
const { defineConfig } = require('@vue/cli-service')
const VueMacros = require('vue-macros/webpack')

module.exports = defineConfig({
  // ...
  // ⚠️ IMPORTANT
  parallel: false,
  configureWebpack: {
    plugins: [
      VueMacros({
        // overrides plugin options
      }),
    ],
  },
})
```

:::

## Configuration

See the [Configurations](./configurations.md) for more details.

```ts twoslash [vue-macros.config.ts]
import { defineConfig } from 'vue-macros'
export default defineConfig({
  // options
})
```

## TypeScript Support

```json {0}
// tsconfig.json
{
  "compilerOptions": {
    // ...
    "types": ["vue-macros/macros-global" /* ... */]
  }
}
```

## Volar Support

For detailed configuration, please refer to the description of the specific macro.

```jsonc [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

### Scoped Plugins

`exportExpose`, `exportProps`, and `exportRender` plugins cannot be used
at the same time unless providing a scope.

```ts twoslash [vue-macros.config.ts]
import { defineConfig } from 'vue-macros'
export default defineConfig({
  exportExpose: {
    include: ['**/export-expose/**'],
  },
  exportProps: {
    include: ['**/export-props/**'],
  },
  exportRender: {
    include: ['**/export-render/**'],
  },
})
```

***

:tada: Congratulations! You have successfully set up Vue Macros.

To learn more about the macros, please visit [All Macros](/macros/) :laughing:.

---

---
url: /macros/chain-call.md
---
# chainCall&#x20;

Extends `defineProps`, support call `withDefaults` as a chain.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    |     :question:     |
|    Vue 2     |     :question:     |
|  TypeScript  | :white\_check\_mark: |
| Volar Plugin |        :x:         |

::: tip

* `chainCall` does not support `definePropsRefs`
* To fully support TypeScript, you need to import this macro from `vue-macros/macros`.

:::

## Basic Usage

```vue
<script setup lang="ts">
const props = defineProps<{
  foo?: string
  bar?: number[]
  baz?: boolean
}>().withDefaults({
  foo: '111',
  bar: () => [1, 2, 3],
})
</script>
```

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const props = withDefaults(
  defineProps<{
    foo?: string
    bar?: number[]
    baz?: boolean
  }>(),
  {
    foo: '111',
    bar: () => [1, 2, 3],
  },
)
</script>
```

:::

Also support [props destructuring](../features/reactivity-transform.md) and JSX:

```vue
<script setup lang="ts">
const { foo } = defineProps<{ foo: string }>().withDefaults({
  foo: '111',
})
</script>
```

## TypeScript

To fully support TypeScript, you need to import this macro from `vue-macros/macros` with specific syntax.

```vue twoslash
<script setup lang="ts">
import { defineProps } from 'vue-macros/macros' with { type: 'macro' }

defineProps<{
  /* ... */
}>().withDefaults({
  /* ... */
})
// ✅ type safe
</script>
```

Works without import assertion, but tsc will report an error:

```ts twoslash
// @errors: 2339
defineProps<{
  /* ... */
}>().withDefaults({
  /* ... */
})
```

---

---
url: /guide/configurations.md
---
# Configurations

## Plugin Options

All features are enabled by default except the following.

#### Disabled by Default

* `exportExpose`
* `exportProps`
* `exportRender`
* `setupSFC`
* `booleanProp`
* `shortBind`
* `defineStyleX`

#### Disabled by Default when Vue >= 3.3

* `defineOptions`
* `defineSlots`
* `hoistStatic`
* `shortEmits`

You can re-enable them by setting the option to `true`.

```ts twoslash [vue-macros.config.(ts,js,json)]
import { defineConfig } from 'vue-macros'
export default defineConfig({
  root: '/your-project-path',

  /**
   * Vue version, 2 or 3.
   *
   * optional, detecting automatically.
   */
  version: 3,

  /** Defaults to true */
  defineModels: {
    // ...
  },

  // Enable features
  defineOptions: true,

  // Disable features
  hoistStatic: false,

  // ... more features
})
```

Refer to the macros and features page for available options.

---

---
url: /macros/define-emit.md
---
# defineEmit&#x20;

Declare single emit one by one using `defineEmit`.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     | :white\_check\_mark: |
|  TypeScript  | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

::: warning

`defineEmit` can not be used with `defineEmits` at same time

:::

## API Reference

```ts
defineEmit<T>(emitName)
defineEmit<T>(emitName, validator)

// emitName parameter can be optional,
// and will be inferred from variable name
const emitName = defineEmit<T>()
```

## Basic Usage

```vue twoslash
<script setup>
// Declare emit
const increment = defineEmit('increment')
// Infer emit name from variable name
const change = defineEmit()
// emit event
increment()
</script>
```

## With Validation

```vue twoslash
<script setup>
// Declare event with validation
const increment = defineEmit('increment', (value) => value < 20)
</script>
```

## TypeScript

```vue twoslash
<script setup lang="ts">
const increment = defineEmit('increment', (value: number) => value < 20)
const decrement = defineEmit<[value: number]>()

increment(2) // pass
// @errors: 2345
increment('2') // TS type error
</script>
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "defineEmit": true,
    },
  },
}
```

---

---
url: /volar/define-generic.md
---
# defineGeneric&#x20;

Declare single generic one by one using `DefineGeneric`.

> Especially useful for `setup-sfc`.

|   Features   |     Supported      |
| :----------: | :----------------: |
| Volar Plugin | :white\_check\_mark: |

## Basic Usage

::: code-group

```vue [App.vue] twoslash
<script setup lang="ts">
// @errors: 2322
defineOptions({
  name: 'App',
})

type T = DefineGeneric<number>

defineProps<{
  foo: T
}>()
</script>

<template>
  <App foo="1" />
</template>
```

:::

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-models.md
---
# defineModels&#x20;

Declaring and mutate `v-model` props as the same as normal variable using the `defineModels`.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

## Options

```ts
VueMacros({
  defineModels: {
    /**
     * Unified mode, only works for Vue 2
     *
     * Converts `modelValue` to `value`
     */
    unified: false,
  },
})
```

## Basic Usage

Requires [`@vueuse/core`](https://www.npmjs.com/package/@vueuse/core), install it by yourself before using.

```vue twoslash
<script setup lang="ts">
const { modelValue, count } = defineModels<{
  modelValue: string
  count: number
}>()

console.log(modelValue.value)
modelValue.value = 'newValue'
</script>
```

::: warning ❌ Object declaring is not supported.

```vue
<script setup lang="ts">
const { modelValue } = defineModels({
  modelValue: String,
})
</script>
```

:::

## With Model Options

```vue twoslash 3-6
<script setup lang="ts">
const { modelValue } = defineModels<{
  modelValue: ModelOptions<
    string,
    { defaultValue: 'something'; deep: true; passive: true }
  >
}>()
</script>
```

## With Reactivity Transform

::: warning

Assignment expression is only supported in `<script setup>` block. In other words invalid in `<template>`.

:::

[`@vueuse/core`](https://www.npmjs.com/package/@vueuse/core) is not required.

```vue twoslash {7-9}
<script setup lang="ts">
let { modelValue, count } = $defineModels<{
  modelValue: string
  count: number
}>()

console.log(modelValue)
modelValue = 'newValue'
count++
</script>
```

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const { modelValue, count } = defineProps<{
  modelValue: string
  count: number
}>()

const emit = defineEmits<{
  (evt: 'update:modelValue', value: string): void
  (evt: 'update:count', value: number): void
}>()

console.log(modelValue)
emit('update:modelValue', 'newValue')
emit('update:count', count + 1)
</script>
```

:::

## Volar Configuration

```jsonc {4,6-9} [tsconfig.json]
{
  "vueCompilerOptions": {
    "target": 3, // or 2.7 for Vue 2
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "defineModels": {
        // Only works when target is 2.7.
        "unified": true,
      },
    },
  },
}
```

---

---
url: /macros/define-options.md
---
# defineOptions&#x20;

Options API can be declared using the `defineOptions` in `<script setup>`, specifically to be able to set `name`, `props`, `emits`, and `render` inside of one function.

For Vue >= 3.3, this feature will be turned off by default.

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Nuxt 3   | :white\_check\_mark: |
|   Vue 2    | :white\_check\_mark: |
| TypeScript | :white\_check\_mark: |

## Installation Standalone Version

if you need `defineOptions` feature only, the standalone version is more appropriate for you.

### Installation

::: code-group

```bash [npm]
npm i -D unplugin-vue-define-options @vue-macros/volar
```

```bash [yarn]
yarn add -D unplugin-vue-define-options @vue-macros/volar
```

```bash [pnpm]
pnpm add -D unplugin-vue-define-options @vue-macros/volar
```

:::

::: code-group

```ts [Vite]
// vite.config.ts
import DefineOptions from 'unplugin-vue-define-options/vite'

export default defineConfig({
  plugins: [DefineOptions()],
})
```

```ts [Rollup]
// rollup.config.js
import DefineOptions from 'unplugin-vue-define-options/rollup'

export default {
  plugins: [DefineOptions()],
}
```

```js [esbuild]
// esbuild.config.js
import { build } from 'esbuild'

build({
  plugins: [require('unplugin-vue-define-options/esbuild')()],
})
```

```js [Webpack]
// webpack.config.js
module.exports = {
  /* ... */
  plugins: [require('unplugin-vue-define-options/webpack')()],
}
```

:::

### TypeScript Support

```json [tsconfig.json]
{
  "compilerOptions": {
    // ...
    "types": ["unplugin-vue-define-options/macros-global" /* ... */]
  }
}
```

## Basic Usage

```vue twoslash {3-4}
<script setup lang="ts">
defineOptions({
  name: 'Foo',
  inheritAttrs: false,
})

defineProps<{
  foo: number
}>()
</script>

<template>
  <Foo :foo="1" />
</template>
```

::: details Compiled Code

```vue twoslash
<script lang="ts">
export default {
  name: 'Foo',
  inheritAttrs: false,
}
</script>

<script setup lang="ts">
defineProps<{
  foo: number
}>()
</script>

<template>
  <Foo :foo="1" />
</template>
```

:::

## JSX in `<script setup>`

```vue twoslash {3-5}
<script setup lang="tsx">
defineOptions({
  render() {
    return <h1>Hello World</h1>
  },
})
</script>
```

::: details Compiled Code

```vue
<script lang="tsx">
export default {
  render() {
    return <h1>Hello World</h1>
  },
}
</script>
```

:::

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-prop.md
---
# defineProp&#x20;

Declare single prop one by one using `defineProp`.

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|       Nuxt 3       | :white\_check\_mark: |
|       Vue 2        | :white\_check\_mark: |
| TypeScript / Volar | :white\_check\_mark: |

::: warning

`defineProp` can not be used in the same file as type-declared `defineProps`.

:::

## Configuration

```ts
VueMacros({
  defineProp: {
    /**
     * 'kevinEdition' | 'johnsonEdition'
     * @default 'kevinEdition'
     */
    edition: 'kevinEdition',
  },
})
```

## Kevin's Edition (Default)

### API Reference

```ts
defineProp<T>(propName)
defineProp<T>(propName, options)

// propName parameter can be optional,
// and will be inferred from variable name
const propName = defineProp<T>()
```

### Basic Usage

```vue twoslash
<script setup lang="ts">
// Declare prop
const count = defineProp('count')

// Infer prop name from variable name
const value = defineProp()

// access prop value
console.log(count.value)
</script>
```

### With Options

```vue twoslash
<script setup lang="ts">
// Declare prop with options
const count = defineProp('count', {
  type: Number,
  required: true,
  default: 0,
  validator: (value: number) => value < 20,
})
</script>
```

### TypeScript

```vue twoslash
<script setup lang="ts">
// Declare prop of type number and infer prop name from variable name
const count = defineProp<number>()
count.value

// Declare prop of TS type boolean with default value
const disabled = defineProp<boolean>('disabled', { default: true })
disabled.value
</script>
```

### With Reactivity Transform

```vue twoslash
<script setup lang="ts">
const foo = $defineProp<string>('foo')

const bar = $(defineProp('bar', { default: 'bar' }))
</script>
```

## Johnson's Edition

### API Reference

```ts
// the prop name will be inferred from variable name
const propName = defineProp<T>()
const propName = defineProp<T>(defaultValue)
const propName = defineProp<T>(defaultValue, required)
const propName = defineProp<T>(defaultValue, required, rest)
```

### Basic Usage

```vue
<script setup lang="ts">
// declare prop `count` with default value `0`
const count = defineProp(0)

// declare required prop `disabled`
const disabled = defineProp(undefined, true)

// access prop value
console.log(count.value, disabled.value)
</script>
```

### With Options

```vue
<script setup lang="ts">
// Declare prop with options
const count = defineProp(0, false, {
  type: Number,
  validator: (value: number) => value < 20,
})
</script>
```

### TypeScript

```vue
<script setup lang="ts">
const count = defineProp<number>()
count.value

// Declare prop of TS type boolean with default value
const disabled = defineProp<boolean>(true)
disabled.value
</script>
```

### With Reactivity Transform

```vue
<script setup lang="ts">
const foo = $defineProp<number>()

const bar = $(defineProp(0, true))
</script>
```

### Volar Configuration

```jsonc {3,7} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "defineProp": {
        // "kevinEdition" | "johnsonEdition"
        "edition": "kevinEdition",
      },
    },
  },
}
```

---

---
url: /macros/define-props.md
---
# defineProps&#x20;

Correct types of destructured props using `$defineProps`.

See also [Vue issue](https://github.com/vuejs/core/issues/6876), [Reactivity Transform RFC](https://github.com/vuejs/rfcs/blob/reactivity-transform/active-rfcs/0000-reactivity-transform.md#defineprops-destructure-details).

|         Features          |     Supported      |
| :-----------------------: | :----------------: |
|           Vue 3           | :white\_check\_mark: |
|          Nuxt 3           | :white\_check\_mark: |
|           Vue 2           | :white\_check\_mark: |
| TypeScript / Volar Plugin | :white\_check\_mark: |

::: warning

[Reactivity Transform](../features/reactivity-transform.md) is required. You should enable it first.

:::

## Basic Usage

```vue twoslash
<script setup lang="ts">
const { foo } = $defineProps<{
  //     ^?
  foo: string[]
}>()

const fooRef = $(foo)
//     ^?
</script>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-props-refs.md
---
# definePropsRefs&#x20;

Returns refs from `defineProps` instead of a reactive object. It can be destructured without losing reactivity.

`toRefs(defineProps())` => `definePropsRefs()`

|         Features          |     Supported      |
| :-----------------------: | :----------------: |
|           Vue 3           | :white\_check\_mark: |
|          Nuxt 3           | :white\_check\_mark: |
|           Vue 2           | :white\_check\_mark: |
| TypeScript / Volar Plugin | :white\_check\_mark: |

## Basic Usage

```vue twoslash {2-3,8}
<script setup lang="ts">
// ✅ won't lose reactivity with destructuring
const { foo, bar } = definePropsRefs<{
  foo: string
  bar: number
}>()

console.log(foo.value, bar.value)
//           ^?
</script>
```

## With Default Value

```vue twoslash {2-3,8}
<script setup lang="ts">
import { withDefaults } from 'vue-macros/macros' with { type: 'macro' }

const { foo } = withDefaults(
  definePropsRefs<{
    foo?: string
  }>(),
  { foo: 'test' },
)

console.log(foo.value)
//           ^?
</script>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-render.md
---
# defineRender&#x20;

Defining render function in `<script setup>` using the `defineRender`.

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Nuxt 3   | :white\_check\_mark: |
|   Vue 2    | :white\_check\_mark: |
| TypeScript | :white\_check\_mark: |

We need more feedback on [RFC Discussion](https://github.com/vuejs/rfcs/discussions/585)!

## Basic Usage

```vue twoslash
<script setup lang="tsx">
// JSX passed directly
defineRender(
  <div>
    <span>Hello</span>
  </div>,
)

// Or using render function
defineRender(() => {
  return (
    <div>
      <h1>Hello World</h1>
    </div>
  )
})
</script>
```

---

---
url: /macros/define-slots.md
---
# defineSlots&#x20;

Declaring type of SFC slots in `<script setup>` using the `defineSlots`.

For Vue >= 3.3, this feature will be turned off by default.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |
|    Vue 2     |        :x:         |

## Basic Usage

### Short Syntax

```vue twoslash
<script setup lang="ts">
defineSlots<{
  // slot name
  title: {
    // scoped slot
    foo: 'bar' | boolean
  }
}>()
</script>
```

### Full Syntax (Official Version)

```vue twoslash
<script setup lang="ts">
defineSlots<{
  title: (scope: { text: string }) => any
}>()
</script>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-stylex.md
---
# defineStyleX&#x20;

Define and consume [StyleX](https://stylexjs.com/) styles in `<script setup>`.

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|       Nuxt 3       | :white\_check\_mark: |
| TypeScript / Volar | :white\_check\_mark: |
|       Vue 2        | :white\_check\_mark: |

## Setup

To use StyleX, you should install and configure StyleX first. The steps could change, you may want to check the [official document](https://stylexjs.com/) and the [document of StyleX bundler integrations](https://stylexjs.com/docs/learn/ecosystem/#third-party-bundler-integrations) for the latest information.

### Vite

```sh
pnpm add @stylexjs/stylex @stylex-extend/core @stylex-extend/vite -D
```

```ts [vite.config.ts] {1,13}
import { stylex } from '@stylex-extend/vite'
import Vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
import VueMacros from 'vue-macros/vite'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue(),
      },
    }),
    stylex(), // Must be placed after Vue Macros
  ],
})
```

```ts [main.ts] {2}
// import StyleX stylesheet, according to https://nonzzz.github.io/stylex-extend/integrations/vite
import 'virtual:stylex.css'
```

## Basic Usage

```vue [App.vue] twoslash
<script setup lang="ts">
const styles = defineStyleX({
  red: { color: 'red' },
})

// ...
// ---cut-start---
declare const vStylex: any
// ---cut-end---
</script>

<template>
  <p v-stylex="styles.red">Red</p>
</template>
```

:::details Compiled Code (with some simplifications)

```vue [App.vue] twoslash
<script lang="ts">
const styles = _stylex_create({
  red: { color: 'red' },
})
</script>

<script setup lang="ts">
import {
  create as _stylex_create,
  props as _stylex_props,
} from '@stylexjs/stylex'
// virtual module to provide runtime code
// ---cut-start---
// @ts-ignore
// ---cut-end---
import stylex_attrs from '/vue-macros/define-stylex/stylex-attrs'

// ...
</script>

<template>
  <p v-bind="stylex_attrs(_stylex_props(styles.red))">Red</p>
</template>
```

:::

## Conditional Styles

Optional and multiple rules are supported.

```vue [App.vue] twoslash
<script setup lang="ts">
defineProps<{ bold?: boolean }>()

const styles = defineStyleX({
  red: { color: 'red' },
  bold: { fontWeight: 'bold' },
})
// ---cut-start---
declare const vStylex: any
// ---cut-end---
</script>

<template>
  <span v-stylex="(styles.red, bold && styles.bold)">Red</span>
</template>
```

:::details Compiled Code (with some simplifications)

```vue [App.vue] twoslash
<script lang="ts">
const styles = _stylex_create({
  red: { color: 'red' },
  bold: { fontWeight: 'bold' },
})
</script>

<script setup lang="ts">
import {
  create as _stylex_create,
  props as _stylex_props,
} from '@stylexjs/stylex'
// ---cut-start---
// @ts-ignore
// ---cut-end---
import stylex_attrs from '/vue-macros/define-stylex/stylex-attrs'

defineProps<{ bold?: boolean }>()
</script>

<template>
  <span v-bind="stylex_attrs(_stylex_props(styles.red, bold && styles.bold))"
    >Red</span
  >
</template>
```

:::

---

---
url: /features/export-expose.md
---
# exportExpose&#x20;

Transform export statement as `defineExpose` params in Vue SFC `script-setup`.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    |         ?          |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

## Usage

Support these syntaxes:

* local variable/function/class
* export with alias
* export from other file
* namespace export
* rename export

### 1. local variable/function/class

```vue twoslash
<script setup lang="ts">
export const foo: string = 'foo'
export const bar = 10
export let baz: string | undefined
export var qux = fn()
// @errors: 2448 2454 2695
export const { a, b, c } = { a: 1, b: 2, c: 3 }

export function fn() {}
export class A {}
</script>
```

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const foo: string = 'foo'
const bar = 10
let baz: string | undefined
const qux = fn()
const { a, b, c } = { a: 1, b: 2, c: 3 }

function fn() {}
class A {}

defineExpose({
  foo,
  bar,
  baz,
  qux,
  a,
  b,
  c,
  fn,
  A,
})
</script>
```

:::

### 2. export with alias

```vue twoslash
<script setup lang="ts">
const foo = ''

export { foo as foo1 }
</script>
```

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const foo = 'foo'

defineExpose({
  foo1: foo,
})
</script>
```

:::

### 3. export from other file

::: code-group

```vue [App.vue] twoslash
<script setup lang="ts">
// #region export-file
const foo = 'foo'
type Foo = string

export { foo, type Foo }
// #endregion export-file
// ---cut---
// @noErrors
export { foo as bar, foo, type Foo } from './types'
</script>
```

<<< ./export-expose.md#export-file{ts} \[types.ts]

:::

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const __MACROS_expose_0 = 'foo'
const __MACROS_expose_1 = 'foo'
type Foo = string
// ---cut---
// @noErrors
import {
  foo as __MACROS_expose_0,
  foo as __MACROS_expose_1,
  type Foo,
} from './types'
defineExpose({
  foo: __MACROS_expose_0,
  bar: __MACROS_expose_1,
})
</script>
```

:::

### 4. namespace export

::: code-group

```vue [App.vue] twoslash
<script setup lang="ts">
const foo = { foo: 'foo' }
// ---cut---
// @noErrors
export * as foo from './types'
</script>
```

```ts [types.ts]
export const foo = 'foo'
```

:::

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const __MACROS_expose_0 = {
  foo: 'foo',
}
// ---cut---
// @noErrors
import * as __MACROS_expose_0 from './types'
defineExpose({
  foo: __MACROS_expose_0,
})
</script>
```

:::

### 5. rename export

```vue
<script setup lang="ts">
const foo = 1
const bar = 1

export { foo } from './types'
export * as bar from './types'
</script>
```

::: details Compiled Code

```vue
<script setup lang="ts">
import { foo as __MACROS_expose_0 } from './types'
import * as __MACROS_expose_1 from './types'

const foo = 1
const bar = 1
defineExpose({
  foo: __MACROS_expose_0,
  bar: __MACROS_expose_1,
})
</script>
```

:::

## Limitations

Currently does't support these following cases:

```ts
// 1. export all ❌
export * from '../types'

// 2. export default ❌
const a = 'a'
export default a
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "exportExpose": true,
    },
  },
}
```

---

---
url: /features/export-props.md
---
# exportProps&#x20;

[Svelte-like Declaring props](https://svelte.dev/docs#component-format-script-1-export-creates-a-component-prop) for Vue.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    |     :question:     |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

## Pre-requisite

[Reactivity Transform](./reactivity-transform.md) is required to use this feature, but it is enabled by default in Vue Macros.

`export let` will be changed to `defineModel`, which is supported in Vue 3.4+.

## Usage

Using export syntax to declare props.

```vue twoslash
<script setup lang="ts">
export let foo: string
export const bar: number = 1 // with default value
</script>
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "exportProps": true,
    },
  },
}
```

---

---
url: /features/export-render.md
---
# exportRender&#x20;

Transform the default export statement, in `<script setup>` of Vue SFC, as a component render function.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    |     :question:     |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

::: tip

This feature depends on `defineRender`, and make sure `defineRender` is not disabled.

:::

## Usage

```vue
<script setup lang="tsx">
// JSX passed directly
export default <div>ok</div>

// Or using render function
export default () => <div>ok</div>
</script>
```

## Volar Configuration

```jsonc {3,7} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "exportRender": true,
    },
  },
}
```

---

---
url: /guide/getting-started.md
---
# Getting Started

Vue Macros is a library that implements unofficial proposals and ideas for Vue,
exploring and extending its features and syntax.

We assume you are already familiar with the basic usages of Vue before you continue.

## Requirements

* Node.js `>= v20.19.0`.
* Vue `>= v2.7` or Vue `>= v3.0`.
  * Some features need Vue `>= v3.2.25`.
* VSCode extension [Vue - Official](https://marketplace.visualstudio.com/items?itemName=Vue.volar) and `vue-tsc` are v{{ version }}
  * Vue Macros will continue to adapt to the latest version as soon as possible, older versions may not be supported.

::: warning
WebStorm is not supported.
:::

## Creating a Vue Macros Project

### Installation

::: code-group

```bash [npm]
npm i -g @vue-macros/cli
```

```bash [yarn]
yarn global add @vue-macros/cli
```

```bash [pnpm]
pnpm add -g @vue-macros/cli
```

:::

This command will install [@vue-macros/cli](https://github.com/vue-macros/vue-macros-cli), the official Vue Macros scaffolding tool.

### Initialization

::: code-group

```bash [npm]
npm create vite@latest my-vue-macros -- --template vue-ts
cd my-vue-macros
vue-macros init
```

```bash [yarn]
yarn create vite my-vue-macros --template vue-ts
cd my-vue-macros
vue-macros init
```

```bash [pnpm]
pnpm create vite my-vue-macros --template vue-ts
cd my-vue-macros
vue-macros init
```

You will be presented with prompts for several optional experimental features.

:::

## Templates

* [Vite](https://github.com/vue-macros/vite)
* [Nuxt](https://github.com/vue-macros/nuxt)
* [Rsbuild](https://github.com/vue-macros/vue3-rsbuild)

🌟 More templates are welcome!

## Nuxt Integration

If you're using [Nuxt](https://nuxt.com/), read the [Nuxt Integration](./nuxt-integration.md).

## Bundler Integrations

If you're using [Vite](https://vitejs.dev/), [Rollup](https://rollupjs.org/), [esbuild](https://esbuild.github.io/), [Webpack](https://webpack.js.org/), or [Rspack](https://www.rspack.dev/), read the [Bundler Integration](./bundler-integration.md).

---

---
url: /features/hoist-static.md
---
# hoistStatic&#x20;

With enabling `hoistStatic`, constants declared in macros of `<script setup>` can be referenced.

For Vue >= 3.3, this feature will be turned off by default.

| Features |     Supported      |
| :------: | :----------------: |
|  Vue 3   | :white\_check\_mark: |
|  Nuxt 3  | :white\_check\_mark: |
|  Vue 2   | :white\_check\_mark: |

## Basic Usage

```vue twoslash
<script setup lang="ts">
const name = 'AppFoo'
defineOptions({
  name,
})
</script>
```

::: details Compiled Code

```vue
<script lang="ts">
const name = 'AppFoo'
export default {
  name,
}
</script>
```

:::

## Magic Comments

```vue
<script setup lang="ts">
// A value that's even not a constant
const name = /* hoist-static */ fn()
defineOptions({
  name,
})
</script>
```

::: details Compiled Code

```vue
<script lang="ts">
const name = fn()
export default {
  name,
}
</script>
```

:::

---

---
url: /features/jsx-directive.md
---
# jsxDirective&#x20;

Vue built-in directives for JSX.

|  Directive  |       Vue 3        |       Vue 2        |       Volar        |
| :---------: | :----------------: | :----------------: | :----------------: |
|   `v-if`    | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
| `v-else-if` | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|  `v-else`   | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|   `v-for`   | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|   `v-on`    | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|  `v-slot`   | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|  `v-html`   | :white\_check\_mark: | :white\_check\_mark: |         /          |
|  `v-once`   | :white\_check\_mark: |        :x:         |         /          |
|  `v-memo`   | :white\_check\_mark: |        :x:         |         /          |

## Options

```ts
interface Options {
  /**
   * @default 'v-'
   */
  prefix?: string
  /**
   * @default 'vue'
   */
  lib?: 'vue' | 'react' | 'preact' | 'solid' | string
}
```

## Usage

### `v-if`, `v-else-if`, `v-else`

```vue twoslash
<script setup lang="tsx">
const { foo } = defineProps<{
  foo: number
}>()

// ---cut-start---
// prettier-ignore
// ---cut-end---
export default () => (
  <>
    <div v-if={foo === 0}>{foo}</div>

    <div v-else-if={foo === 1}>{foo}</div>
    //                          ^?

    <div v-else>{foo}</div>
    //           ^?
  </>
)
</script>
```

### `v-for`

```vue twoslash
<script setup lang="tsx">
export default () => (
  <div v-for={(item, index) in 4} key={index}>
    {item}
  </div>
)
</script>
```

### `v-slot`

::: code-group

```vue [App.vue] twoslash
<script lang="tsx" setup>
// #region v-slot
import type { FunctionalComponent } from 'vue'

export const Comp: FunctionalComponent<
  {},
  {},
  {
    default: () => any
    slot: (scope: { bar: number }) => any
    slots: (scope: { baz: boolean }) => any
  }
> = () => <div />
// #endregion v-slot
// ---cut---
// @noErrors
import { Comp } from './Comp.tsx'

// ---cut-start---
// prettier-ignore
// ---cut-end---
export default () => (
  <Comp>
    default slot...
    <template v-slot:slot={{ bar }}>
      //              ^|
      {bar}
    </template>
  </Comp>
)
</script>
```

<<< ./jsx-directive.md#v-slot{tsx} \[Child.tsx]

:::

### `v-on`

::: warning

`v-on` only supports binding to an object of event / listener pairs without an argument.

:::

```tsx
<form v-on={{ submit }} />
```

## Dynamic Arguments

It is also possible to use a variable in a directive argument by wrapping it with a pair of `


  
  
  
  
  vue-macros.dev | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


  :

`v-model`

::: code-group

```vue [App.vue] twoslash
<script setup lang="tsx">
// ---cut-start---
// #region v-model
import { ref, type FunctionalComponent } from 'vue'

export const Comp: FunctionalComponent<
  {
    model: string
    models: string[]
  },
  {
    'update:model': [value: string]
    'update:models': [value: string[]]
  }
> = () => <div />
// #endregion v-model
// ---cut-end---
// @noErrors
import { Comp } from './Comp.tsx'

const name = ref('model')
const model = defineModel<string>()

export default () => (
  <Comp
    v-model:$name$={model.value}
    v-model:model={model.value}
    //       ^|
  />
)
</script>
```

<<< ./jsx-directive.md#v-model{tsx} \[Comp.tsx]

:::

`v-slot`

::: code-group

```vue [App.vue] twoslash
<script setup lang="tsx">
// ---cut-start---
// #region v-slot-dynamic
import type { FunctionalComponent } from 'vue'

export const Comp: FunctionalComponent<
  {},
  {},
  {
    default: (scope: { foo: string }) => any
    title: (scope: { bar: number }) => any
  }
> = () => <div />
// #endregion v-slot-dynamic
// ---cut-end---
// @noErrors
import { Comp } from './Comp.tsx'

const slots = defineSlots<{
  default: (scope: { foo: string }) => any
  title: (scope: { bar: number }) => any
}>()

// ---cut-start---
// prettier-ignore
// ---cut-end---
export default () => (
  <Comp>
    <template v-for={(Slot, name) in slots} v-slot:$name$={scope}>
      //                                             ^?
      <Slot {...scope} />
    </template>
  </Comp>
)
</script>
```

<<< ./jsx-directive.md#v-slot-dynamic{tsx} \[Comp.tsx]

:::

## Modifiers

Modifiers are special postfixes denoted by a `_`, which indicate that a directive should be bound in some special way.

```tsx
<form onSubmit_prevent>
  <input v-model_number={value} />
</form>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /volar/jsx-ref.md
---
# jsxRef&#x20;

Automatically infer type for `useRef`.

| Features |     Supported      |
| :------: | :----------------: |
|  Volar   | :white\_check\_mark: |

## Setup Auto Import

::: code-group

```ts [vite.config.ts]
import AutoImport from 'unplugin-auto-import/vite'

export default defineConfig({
  plugins: [
    AutoImport({
      imports: [
        {
          from: 'vue',
          imports: [['shallowRef', 'useRef']],
        },
      ],
    }),
  ],
})
```

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  imports: {
    presets: [
      {
        from: 'vue',
        imports: [['shallowRef', 'useRef']],
      },
    ],
  },
})
```

:::

## Basic Usage

::: code-group

```vue [App.vue] twoslash
<script lang="tsx">
// #region comp
import { defineComponent } from 'vue'

export const Comp = defineComponent({
  setup() {
    return { foo: 1 }
  },
})
// #endregion comp
// ---cut---
import { useRef } from 'vue-macros/runtime'
// Or import { shallowRef as useRef } from 'vue'
// @noErrors
import { Comp } from './Comp.ts'

export default defineComponent(() => {
  const comp = useRef()
  comp.value?.foo
  //           ^?

  return () => (
    <>
      <Comp ref={comp} />
    </>
  )
})
</script>
```

<<< ./jsx-ref.md#comp{ts} \[Comp.ts]

:::

## Volar Configuration

```jsonc [tsconfig.json] {3,6}
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "jsxRef": {
        "alias": ["useRef"],
      },
    },
  },
}
```

---

---
url: /guide/migration-v3.md
---
# Migration from v2 to v3

## Unified Version Management

Initially, we used [`changesets`](https://github.com/changesets/changesets) to
manage the versions of all packages in the monorepo. However, after two years of experimentation,
we decided to adopt a single-version strategy in v3,
where all sub-packages share the same version number, similar to Vue and Babel.
This decision stemmed from our observation that when a sub-package underwent a major change or minor update,
the version number of the main package did not adequately reflect these changes.

For example, when `@vue-macros/define-prop` introduced a breaking change,
how should `unplugin-vue-macros` release a new version?
Should it be a minor or a patch release? When users updated `unplugin-vue-macros`,
they couldn’t easily determine whether the update was due to changes in `@vue-macros/define-prop`.

Therefore, after Anthony proposed [Epoch Semantic Versioning](https://antfu.me/posts/epoch-semver),
we decided to adopt a more frequent major version update strategy,
with all packages sharing the same version number and maintaining a single unified changelog.

## Main Package Rename

We have renamed the main package from `unplugin-vue-macros` to **`vue-macros`**.
After the official release of v3, `unplugin-vue-macros` will be marked as deprecated.

As a result, you will need to update your `package.json` and the import statements for Vue Macros:

```diff
 // package.json
 {
   "devDependencies": {
-    "unplugin-vue-macros": "^2.14.5"
+    "vue-macros": "^3.0.0"
   }
 }
```

```diff
- import { $ref } from 'unplugin-vue-macros/macros'
+ import { $ref } from 'vue-macros/macros'

- import VueMacros from 'unplugin-vue-macros/vite'
+ import VueMacros from 'vue-macros/vite'
```

## Dropping Vue 2 Support

Vue 2 reached its end of life (EOL) at the end of 2023, so we have decided to drop support for Vue 2 in v3.
If you are still using Vue 2, we recommend continuing with v2 or
considering our [paid support plan](https://github.com/vue-macros/vue-macros/issues/373).

## Node.js Compatibility Changes

In v3, we have dropped support for Node.js versions below 20.19.
This means the minimum Node.js version requirement for v3 is `20.19.0`.
Additionally, we have removed CommonJS (CJS) outputs and now only provide ECMAScript modules (ESM).

## Dropping Webpack 4 Support

Since Webpack 4 cannot run in Node.js 18 or later environments,
we have also dropped support for Webpack 4 and Vue CLI 4.
We recommend upgrading to modern build tools like Vite or Rspack.

---

---
url: /features/named-template.md
---
# namedTemplate&#x20;

::: warning

Not actively maintained now. Try [createReusableTemplate](https://vueuse.org/core/createReusableTemplate/) instead.

:::

With enabling `namedTemplate`, `<template>` can be referenced like a variable.

Sometimes we need to reverse the order of the very simple components, and don't want to give the features of Vue template up and use JSX/TSX. Then this feature is much helpful.

If you support this feature, you can go to [the discussion](https://github.com/vuejs/core/discussions/6898) and hit like :+1: or comment.

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|      Vue 3.3       |        :x:         |
|       Nuxt 3       |        :x:         |
|       Vue 2        |        :x:         |
| TypeScript / Volar |        :x:         |

## Basic Usage

```vue {5-7,10-12,16-18}
<script setup>
const pager = 'top'
</script>

<template name="pager">
  <span>This is pager</span>
</template>

<template>
  <template v-if="pager === 'top'">
    <template is="pager" />
  </template>

  <span>Here is data table</span>

  <template v-if="pager === 'bottom'">
    <template is="pager" />
  </template>
</template>
```

## Known Usage

* TypeScript / Volar support is not yet completed.

---

---
url: /features/reactivity-transform.md
---
# Reactivity Transform&#x20;

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|       Nuxt 3       | :white\_check\_mark: |
|       Vue 2        | :white\_check\_mark: |
| TypeScript / Volar | :white\_check\_mark: |

## Installation Standalone Version

if you need Reactivity Transform feature only, the standalone version is more appropriate for you.

### Installation

::: code-group

```bash [npm]
npm i -D @vue-macros/reactivity-transform
```

```bash [yarn]
yarn add -D @vue-macros/reactivity-transform
```

```bash [pnpm]
pnpm add -D @vue-macros/reactivity-transform
```

:::

::: code-group

```ts [Vite]
// vite.config.ts
import ReactivityTransform from '@vue-macros/reactivity-transform/vite'

export default defineConfig({
  plugins: [ReactivityTransform()],
})
```

```ts [Rollup]
// rollup.config.js
import ReactivityTransform from '@vue-macros/reactivity-transform/rollup'

export default {
  plugins: [ReactivityTransform()],
}
```

```js [esbuild]
// esbuild.config.js
import { build } from 'esbuild'

build({
  plugins: [require('@vue-macros/reactivity-transform/esbuild')()],
})
```

```js [Webpack]
// webpack.config.js
module.exports = {
  /* ... */
  plugins: [require('@vue-macros/reactivity-transform/webpack')()],
}
```

:::

### TypeScript Support

```json [tsconfig.json]
{
  "compilerOptions": {
    // ...
    "types": ["@vue-macros/reactivity-transform/macros-global" /* ... */]
  }
}
```

## Refs vs. Reactive Variables {#refs-vs-reactive-variables}

Ever since the introduction of the Composition API, one of the primary unresolved questions is the use of refs vs. reactive objects. It's easy to lose reactivity when destructuring reactive objects, while it can be cumbersome to use `.value` everywhere when using refs. Also, `.value` is easy to miss if not using a type system.

Reactivity Transform is a compile-time transform that allows us to write code like this:

```vue twoslash
<script setup>
let count = $ref(0)

console.log(count)

function increment() {
  count++
}
</script>

<template>
  <button @click="increment">{{ count }}</button>
</template>
```

The `$ref()` method here is a **compile-time macro**: it is not an actual method that will be called at runtime. Instead, the Vue compiler uses it as a hint to treat the resulting `count` variable as a **reactive variable.**

Reactive variables can be accessed and re-assigned just like normal variables, but these operations are compiled into refs with `.value`. For example, the `<script>` part of the above component is compiled into:

```js{5,8} twoslash
import { ref } from 'vue'

let count = ref(0)

console.log(count.value)

function increment() {
  count.value++
}
```

Every reactivity API that returns refs will have a `


  
  
  
  
  vue-macros.dev | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


  -prefixed macro equivalent. These APIs include:

* [`ref`](https://vuejs.org/api/reactivity-core#ref) -> `$ref`
* [`computed`](https://vuejs.org/api/reactivity-core#computed) -> `$computed`
* [`shallowRef`](https://vuejs.org/api/reactivity-advanced#shallowref) -> `$shallowRef`
* [`customRef`](https://vuejs.org/api/reactivity-advanced#customref) -> `$customRef`
* [`toRef`](https://vuejs.org/api/reactivity-utilities#toref) -> `$toRef`

These macros are globally available and do not need to be imported when Reactivity Transform is enabled, but you can optionally import them from `vue-macros/macros` or `@vue-macros/reactivity-transform/macros-global` if you want to be more explicit:

```js twoslash
import { $ref } from 'vue-macros/macros'
// for standalone version:
// import { $ref } from '@vue-macros/reactivity-transform/macros-global'

const count = $ref(0)
```

## Destructuring with `$()` {#destructuring-with}

It is common for a composition function to return an object of refs, and use destructuring to retrieve these refs. For this purpose, reactivity transform provides the **`$()`** macro:

```js twoslash
import { ref } from 'vue'
function useMouse() {
  return {
    x: ref(0),
    y: ref(0),
  }
}
// ---cut---
const { x, y } = $(useMouse())

console.log(x, y)
```

Compiled output:

```js twoslash
import { ref, toRef } from 'vue'
function useMouse() {
  return {
    x: ref(0),
    y: ref(0),
  }
}
// ---cut---
const __temp = useMouse()
const x = toRef(__temp, 'x')
const y = toRef(__temp, 'y')

console.log(x.value, y.value)
```

Note that if `x` is already a ref, `toRef(__temp, 'x')` will simply return it as-is and no additional ref will be created. If a destructured value is not a ref (e.g. a function), it will still work - the value will be wrapped in a ref so the rest of the code works as expected.

`$()` destructure works on both reactive objects **and** plain objects containing refs.

## Convert Existing Refs to Reactive Variables with `$()` {#convert-existing-refs-to-reactive-variables-with}

In some cases we may have wrapped functions that also return refs. However, the Vue compiler won't be able to know ahead of time that a function is going to return a ref. In such cases, the `$()` macro can also be used to convert any existing refs into reactive variables:

```js twoslash
import { ref } from 'vue'

function myCreateRef() {
  return ref(0)
}

const count = $(myCreateRef())
```

## Reactive Props Destructure {#reactive-props-destructure}

There are two pain points with the current `defineProps()` usage in `<script setup>`:

1. Similar to `.value`, you need to always access props as `props.x` in order to retain reactivity. This means you cannot destructure `defineProps` because the resulting destructured variables are not reactive and will not update.

2. When using the [type-only props declaration](https://vuejs.org/api/sfc-script-setup.html#typescript-only-features), there is no easy way to declare default values for the props. We introduced the `withDefaults()` API for this exact purpose, but it's still clunky to use.

We can address these issues by applying a compile-time transform when `defineProps` is used with destructuring, similar to what we saw earlier with `$()`:

```vue twoslash
<script setup lang="ts">
import { watchEffect } from 'vue'

interface Props {
  msg: string
  count?: number
  foo?: string
}

const {
  msg,
  // default value just works
  count = 1,
  // local aliasing also just works
  // here we are aliasing `props.foo` to `bar`
  foo: bar,
} = defineProps<Props>()

watchEffect(() => {
  // will log whenever the props change
  console.log(msg, count, bar)
})
</script>
```

The above will be compiled into the following runtime declaration equivalent:

```ts twoslash
import { defineComponent, watchEffect } from 'vue'

export default defineComponent({
  props: {
    msg: { type: String, required: true },
    count: { type: Number, default: 1 },
    foo: String,
  },
  setup(props) {
    watchEffect(() => {
      console.log(props.msg, props.count, props.foo)
    })
  },
})
```

## Retaining Reactivity Across Function Boundaries {#retaining-reactivity-across-function-boundaries}

While reactive variables relieve us from having to use `.value` everywhere, it creates an issue of "reactivity loss" when we pass reactive variables across function boundaries. This can happen in two cases:

### Passing into function as argument {#passing-into-function-as-argument}

Given a function that expects a ref as an argument, e.g.:

```ts twoslash
import { watch, type Ref } from 'vue'

function trackChange(x: Ref<number>) {
  watch(x, (x) => {
    console.log('x changed!')
  })
}

const count = $ref(0)
// @errors: 2345
trackChange(count) // doesn't work!
```

The above case will not work as expected because it compiles to:

```ts
const count = ref(0)
trackChange(count.value)
```

Here `count.value` is passed as a number, whereas `trackChange` expects an actual ref. This can be fixed by wrapping `count` with `$()` before passing it:

```diff
let count = $ref(0)
- trackChange(count)
+ trackChange($(count))
```

The above compiles to:

```js
import { ref } from 'vue'

const count = ref(0)
trackChange(count)
```

As we can see, `$()` is a macro that serves as an **escape hint**: reactive variables inside `$()` will not get `.value` appended.

### Returning inside function scope {#returning-inside-function-scope}

Reactivity can also be lost if reactive variables are used directly in a returned expression:

```ts twoslash
function useMouse() {
  const x = $ref(0)
  const y = $ref(0)

  // listen to mousemove...

  // doesn't work!
  return {
    x,
    y,
  }
}
```

The above return statement compiles to:

```ts
return {
  x: x.value,
  y: y.value,
}
```

In order to retain reactivity, we should be returning the actual refs, not the current value at return time.

Again, we can use `$()` to fix this. In this case, `$()` can be used directly on the returned object - any reference to reactive variables inside the `$()` call will retain the reference to their underlying refs:

```ts twoslash
function useMouse() {
  const x = $ref(0)
  const y = $ref(0)

  // listen to mousemove...

  // fixed
  return $({
    x,
    y,
  })
}
```

### Using `$()` on destructured props {#using-on-destructured-props}

`$()` works on destructured props since they are reactive variables as well. The compiler will convert it with `toRef` for efficiency:

```vue twoslash
<script setup lang="ts">
import type { Ref } from 'vue'
function passAsRef(count: Ref<number>) {
  return count
}
// ---cut---
const { count } = defineProps<{ count: number }>()

passAsRef($(count))
</script>
```

compiles to:

```ts twoslash
import { defineComponent, toRef, type Ref } from 'vue'
function passAsRef(count: Ref<number>) {
  return count
}
// ---cut---
export default defineComponent({
  props: {
    count: { type: Number, required: true },
  },
  setup(props) {
    const __props_count = toRef(props, 'count')
    passAsRef(__props_count)
  },
})
```

## TypeScript Integration  {#typescript-integration}

Vue provides typings for these macros (available globally) and all types will work as expected. There are no incompatibilities with standard TypeScript semantics, so the syntax will work with all existing tooling.

This also means the macros can work in any files where valid JS / TS are allowed - not just inside Vue SFCs.

Since the macros are available globally, their types need to be explicitly referenced (e.g. in a `env.d.ts` file):

```ts [env.d.ts]
/// <reference types="vue-macros/macros-global" />

// or for standalone version:
/// <reference types="@vue-macros/reactivity-transform/macros-global" />
```

When explicitly importing the macros from `vue-macros/macros` or `@vue-macros/reactivity-transform/macros-global`, the type will work without declaring the globals.

---

---
url: /features/script-lang.md
---
# scriptLang&#x20;

Set the default language for `<script>` block.

::: tip
Convert `<script setup>` to `<script setup lang="ts">`.
:::

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

## Options

```ts
interface Options {
  /**
   * @default 'ts'
   */
  defaultLang?: 'ts' | 'tsx' | 'jsx' | string
}
```

## Usage

```vue twoslash
<script setup>
defineProps<{
  foo: string
}>()
</script>
```

## Volar Configuration

```jsonc {3,5-7} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "scriptLang": {
        "defaultLang": "ts",
      },
    },
  },
}
```

---

---
url: /volar/script-sfc.md
---
# scriptSFC&#x20;

Enabled Volar support for `.ts` | `.tsx` files.

|   Features   |     Supported      |
| :----------: | :----------------: |
| Volar Plugin | :white\_check\_mark: |

## Basic Usage

### With `jsxDirective`

::: code-group

```tsx [App.tsx]
export default ({ foo }: { foo: number }) => (
  <div v-if={foo === 1}>{foo}</div>
  //                     ^ will be inferred as 1
)
```

:::

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["@vue-macros/volar"],
    "vueMacros": {
      "scriptSFC": true,
    },
  },
}
```

---

---
url: /macros/setup-component.md
---
# setupComponent&#x20;

::: tip

`defineRender` cannot be disabled when using `setupComponent`.

Files in `node_modules` will be ignored by default.

:::

With `defineSetupComponent`, `<script setup>` code can be put in **pure JS/TS(X)** without [Vue Language Tools (Volar)](https://github.com/johnsoncodehk/volar) extension.

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Nuxt 3   |        :x:         |
|   Vue 2    |        :x:         |
| TypeScript |        :x:         |

See also [Vue Vine](https://vue-vine.dev/) - another style for Vue functional component.

## Basic Usage

```tsx twoslash
export const App = defineSetupComponent(() => {
  defineProps<{
    foo: string
  }>()

  defineEmits<{
    (evt: 'change'): void
  }>()

  defineOptions({
    name: 'App',
  })

  // ...
  return <div />
})
```

## Type Annotation

```ts twoslash
export const App: SetupFC = () => {
  defineProps<{
    foo: string
  }>()

  defineEmits<{
    (evt: 'change'): void
  }>()

  defineOptions({
    name: 'App',
  })
}
```

## Known Issues

* TypeScript support is not yet completed.
* The source map does not correspond properly.

---

---
url: /volar/setup-jsdoc.md
---
# setupJsdoc&#x20;

Define the component's JSDoc in the script setup block.

|   Features   |     Supported      |
| :----------: | :----------------: |
| Volar Plugin | :white\_check\_mark: |

## Basic Usage

````vue twoslash
<script setup lang="tsx">
/**
 * @example
 * ```vue
 * <Comp :foo="1" />
 * ```
 */
const Comp = () => <div />
// ---cut---
// @noErrors
import Comp from './Comp.vue'
//     ^?
</script>

<template>
  <Comp />
</template>
````

### There are two places to define

1. The first line of the script setup block.

````vue
<script setup lang="ts">
/**
 * @example
 * ```vue
 * <Comp :foo="1" />
 * ```
 */

defineProps<{
  foo: number
}>()
</script>
````

2. Above the `export default` expression.

::: tip

This feature depends on `exportRender`, and make sure `exportRender` is not disabled.

:::

````vue
<script setup lang="tsx">
defineProps<{
  foo: number
}>()

/**
 * @example
 * ```vue
 * <Comp :foo="1" />
 * ```
 */
export default <div />
</script>
````

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/setup-sfc.md
---
# setupSFC&#x20;

::: tip

If you're using `setupSFC`, then `defineRender` cannot be disabled.

:::

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|       Nuxt 3       | :white\_check\_mark: |
|       Vue 2        | :white\_check\_mark: |
| TypeScript / Volar | :white\_check\_mark: |

## Setup

::: code-group

```ts {7-14} [Vite]
// vite.config.ts
import Vue from '@vitejs/plugin-vue'
import VueMacros from 'vue-macros/vite'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue({
          include: [/\.vue$/, /\.setup\.[cm]?[jt]sx?$/],
          //                   ⬆️ setupSFC pattern need to be added
        }),
      },
    }),
  ],
})
```

```ts {6-13} [Rollup]
import Vue from 'unplugin-vue/rollup'
import VueMacros from 'vue-macros/rollup'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue({
          include: [/\.vue$/, /\.setup\.[cm]?[jt]sx?$/],
          //                   ⬆️ setupSFC pattern need to be added
        }),
      },
    }),
  ],
})
```

```[🚧 esbuild]
🚧
```

```[🚧 Webpack]
🚧
```

:::

## Basic Usage

```tsx twoslash
// Foo.setup.tsx
defineProps<{
  foo: string
}>()

defineEmits<{
  (evt: 'change'): void
}>()

export default () => (
  <div>
    <h1>Hello World</h1>
  </div>
)
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "setupSFC": true,
    },
  },
}
```

---

---
url: /features/short-bind.md
---
# shortBind&#x20;

`:value` -> `:value="value"`

Same-name shorthand for binding prop. If the attribute has the same name with the JavaScript value being bound, the syntax can be further shortened to omit the attribute value.

For Vue >= 3.4, this feature will be turned off by default.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     |        :x:         |
| Volar Plugin | :white\_check\_mark: |

## Usage

### Basic Usage

```vue twoslash
<script setup>
const value = 'foo'
</script>

<template>
  <input :value />
  <!-- => <input :foo="value" /> -->
</template>
```

### With `shortVmodel`

```vue
<template>
  <Comp ::value />
  <!-- => <Comp ::foo="foo" /> => <Comp v-model:foo="foo" /> -->
  <Comp $foo />
  <!-- => <Comp $foo="foo" /> => <Comp v-model:foo="foo" /> -->
  <Comp *foo />
  <!-- => <Comp *foo="foo" /> => <Comp v-model:foo="foo" /> -->
</template>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/short-emits.md
---
# shortEmits&#x20;

Simplify the definition of emits.

For Vue >= 3.3, this feature will be turned off by default.

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Vue 2    | :white\_check\_mark: |
| TypeScript | :white\_check\_mark: |

## Basic Usage

```vue twoslash
<script setup lang="ts">
import { defineEmits } from 'vue-macros/macros'

const emits = defineEmits<{
  // tuple
  'update:modelValue': [val: string]
  // function
  update: (val: string) => void
}>()
</script>
```

Using type `ShortEmits` or for short `SE`.

```vue twoslash
<script setup lang="ts">
const emits = defineEmits<
  SE<{
    // tuple
    'update:modelValue': [val: string]
    // function
    update: (val: string) => void
  }>
>()
</script>
```

## Difference with Official Version

* function style of declaration is not supported by official version.

---

---
url: /macros/short-vmodel.md
---
# shortVmodel&#x20;

A shorthand for `v-model`.

`v-model` -> `::` / `


  
  
  
  
  vue-macros.dev | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


   / `*`

If you have any questions about this feature, you can comment on [RFC Discussion](https://github.com/vuejs/rfcs/discussions/395).

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     |        :x:         |
| Volar Plugin | :white\_check\_mark: |

## Options

```ts
interface Options {
  /**
   * @default '
#x27; */ prefix?: '::' | '
#x27; | '*' } ``` ## Usage ### ` vue-macros.dev | Top Sites | DialtoneApp Dollar Sign (Default) ```vue <template> <input $="msg" /> <!-- => <input v-model="msg" /> --> <demo $msg="msg" /> <!-- => <input v-model:msg="msg" /> --> </template> ``` ### `::` Double Binding ```vue <template> <!-- prettier-ignore --> <input ::="msg" /> <!-- => <input v-model="msg" /> --> <demo ::msg="msg" /> <!-- => <input v-model:msg="msg" /> --> </template> ``` ### `*` Asterisk Sign ```vue <template> <input *="msg" /> <!-- => <input v-model="msg" /> --> <demo *msg="msg" /> <!-- => <input v-model:msg="msg" /> --> </template> ``` ## Volar Configuration ```jsonc {3,5-7} [tsconfig.json] { "vueCompilerOptions": { "plugins": ["vue-macros/volar"], "vueMacros": { "shortVmodel": { "prefix": "
quot;, }, }, }, } ``` ## Known Issues * Prettier will format `::=` to `:=` (e.g. `<div ::="msg" />` -> `<div :="msg" />`). The comment `<!-- prettier-ignore -->` is required if prefix is `::`. --- --- url: /volar/template-ref.md --- # templateRef&#x20; Automatically infer type for `templateRef` (from [VueUse](https://vueuse.org/core/templateRef/)) and `useTemplateRef` (Vue 3.5+). ::: warning This feature is officially supported since Volar (`vue-tsc`) v2.1.0. Vue Macros is no longer offering this feature as a plugin. ::: | Features | Supported | | :------: | :----------------: | | Volar | :white\_check\_mark: | ## Basic Usage ::: code-group ```vue [App.vue] twoslash <script setup lang="ts"> // #region comp import { defineComponent } from 'vue' export const Comp = defineComponent({ setup() { return { foo: 1 } }, }) // #endregion comp // ---cut--- import { templateRef } from '@vueuse/core' // @noErrors import { Comp } from './Comp.ts' const comp = templateRef('comp') comp.value?.foo // ^? </script> <template> <Comp ref="comp" /> </template> ``` <<< ./template-ref.md#comp{ts} \[Comp.ts] ::: ## Volar Configuration No configuration required. --- --- url: /macros.md --- # Usage List of all available macros. Please make sure `vue-macros` is set up correctly. If you haven't yet, read [Getting Started](../guide/getting-started.md) first. ## Implemented by Vue 3.3 * [defineOptions](./define-options.md) * [defineSlots](./define-slots.md) * [shortEmits](./short-emits.md) ## Stable Features * [defineModels](./define-models.md) * [defineProps](./define-props.md) * [definePropsRefs](./define-props-refs.md) * [defineRender](./define-render.md) * [shortVmodel](./short-vmodel.md) ## Experimental Features * [defineProp](./define-prop.md) * [defineEmit](./define-emit.md) * [setupComponent](./setup-component.md) * [setupSFC](./setup-sfc.md) * [chainCall](./chain-call.md) * [defineStyleX](./define-stylex.md)

Top SitesVue Macros

Machine Readiness

Stored receipt and evidence

Overall

27

Readable

90

Callable

0

Commerce

0

Payment

0

Machine Access

Inspect the site's MCP endpoint

Open MCP explorer

DialtoneApp can scan the stored discovery files for this domain, try the MCP initialize handshake, and show the raw protocol transcript.

Purchase boundary

read only

Control boundary

unknown

Payment rails

None

Payment providers

None

Payment methods

None

Payment protocols

None

Payment assets

None

Payment networks

None

Capabilities

None

Verified payment surface

No

Crypto only

No

Readable docs

llms, llms-full

Products

0

Variants

0

Priced variants

0

Currencies

0

Offers

0

Priced offers

0

Priced actions

0

Samples

Offer samples

No stored offer samples.

Samples

Action samples

No stored action samples.

Samples

Product samples

No stored product samples.

Document

robots.txt

Not stored for this site.

Document

llms.txt

Open llms.txt
# Vue Macros

> Modern Way to Writing Vue App

Explore more macros and syntax sugar to Vue.

## Table of Contents

- [&#x20;ESLint Integration&#x20;](/guide/eslint-integration.md)
- [&#x20;Nuxt Integration&#x20;](/guide/nuxt-integration.md)
- [Astro Integration&#x20;](/guide/astro-integration.md)
- [betterDefine&#x20;](/features/better-define.md)
- [booleanProp&#x20;](/features/boolean-prop.md)
- [Bundler Integration&#x20;](/guide/bundler-integration.md)
- [chainCall&#x20;](/macros/chain-call.md)
- [Configurations](/guide/configurations.md)
- [defineEmit&#x20;](/macros/define-emit.md)
- [defineGeneric&#x20;](/volar/define-generic.md)
- [defineModels&#x20;](/macros/define-models.md)
- [defineOptions&#x20;](/macros/define-options.md)
- [defineProp&#x20;](/macros/define-prop.md)
- [defineProps&#x20;](/macros/define-props.md)
- [definePropsRefs&#x20;](/macros/define-props-refs.md)
- [defineRender&#x20;](/macros/define-render.md)
- [defineSlots&#x20;](/macros/define-slots.md)
- [defineStyleX&#x20;](/macros/define-stylex.md)
- [exportExpose&#x20;](/features/export-expose.md)
- [exportProps&#x20;](/features/export-props.md)
- [exportRender&#x20;](/features/export-render.md)
- [Getting Started](/guide/getting-started.md)
- [hoistStatic&#x20;](/features/hoist-static.md)
- [jsxDirective&#x20;](/features/jsx-directive.md)
- [jsxRef&#x20;](/volar/jsx-ref.md)
- [Migration from v2 to v3](/guide/migration-v3.md)
- [namedTemplate&#x20;](/features/named-template.md)
- [Reactivity Transform&#x20;](/features/reactivity-transform.md)
- [scriptLang&#x20;](/features/script-lang.md)
- [scriptSFC&#x20;](/volar/script-sfc.md)
- [setupComponent&#x20;](/macros/setup-component.md)
- [setupJsdoc&#x20;](/volar/setup-jsdoc.md)
- [setupSFC&#x20;](/macros/setup-sfc.md)
- [shortBind&#x20;](/features/short-bind.md)
- [shortEmits&#x20;](/macros/short-emits.md)
- [shortVmodel&#x20;](/macros/short-vmodel.md)
- [templateRef&#x20;](/volar/template-ref.md)
- [Usage](/macros.md)

Document

llms-full.txt

Open llms-full.txt
---
url: /guide/eslint-integration.md
---
# &#x20;ESLint Integration&#x20;

## Installation

::: code-group

```bash [pnpm]
pnpm add -D @vue-macros/eslint-config
```

```bash [yarn]
yarn add -D @vue-macros/eslint-config
```

```bash [npm]
npm i -D @vue-macros/eslint-config
```

:::

## Configuration

### Flat Configuration

```js [eslint.config.js]
import vueMacros from '@vue-macros/eslint-config/flat'
export default [
  vueMacros,
  // ...your other configurations
]
```

### Legacy Configuration

```jsonc [.eslintrc]
{
  "extends": [
    "@vue-macros/eslint-config",
    // ...your other configurations
  ],
}
```

---

---
url: /guide/nuxt-integration.md
---
# &#x20;Nuxt Integration&#x20;

### Installation

::: code-group

```bash [npm]
npm i -D @vue-macros/nuxt
```

```bash [yarn]
yarn add -D @vue-macros/nuxt
```

```bash [pnpm]
pnpm add -D @vue-macros/nuxt
```

:::

## Configuration

```ts [nuxt.config.ts]
export default {
  modules: [
    '@vue-macros/nuxt',
    // ...
  ],
  macros: {
    // overrides config options
  },
}
```

***

:tada: Congratulations! That's all.

To learn more about the macros, please visit [All Macros](/macros/) :laughing:.

---

---
url: /guide/astro-integration.md
---
# Astro Integration&#x20;

### Installation

::: code-group

```bash [npm]
npm i -D @vue-macros/astro
```

```bash [yarn]
yarn add -D @vue-macros/astro
```

```bash [pnpm]
pnpm add -D @vue-macros/astro
```

:::

## Configuration

```ts [astro.config.mjs]
import Vue from '@astrojs/vue'
import Macros from '@vue-macros/astro'
import { defineConfig } from 'astro/config'

export default defineConfig({
  integrations: [
    Vue(),
    Macros({
      // overrides config options
    }),
  ],
})
```

## TypeScript Support & Volar Support

See the corresponding chapter on [Bundler Integration](./bundler-integration.md#typescript-support)

***

:tada: Congratulations! That's all.

To learn more about the macros, please visit [All Macros](/macros/) :laughing:.

---

---
url: /features/better-define.md
---
# betterDefine&#x20;

With enabling `betterDefine`, imported types are supported in `<script setup>` type-based-macros.

[Related issue](https://github.com/vuejs/core/issues/4294)

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Nuxt 3   | :white\_check\_mark: |
|   Vue 2    | :white\_check\_mark: |
| TypeScript | :white\_check\_mark: |

## Basic Usage

::: code-group

```vue twoslash [App.vue]
<script setup lang="ts">
// #region basic
type BaseProps = {
  title: string
}

export type { BaseProps }
// #endregion basic
// ---cut---
// @noErrors
import type { BaseProps } from './types'

interface Props extends BaseProps {
  foo: string
}
const props = defineProps<Props>()
</script>
```

<<< ./better-define.md#basic{ts} \[types.ts]

:::

## ⚠️ Limitations

### Complex types

Complex types are not supported in some key places. For example:

#### What are Complex Types?

* All utility types
  * [Built-in types](https://www.typescriptlang.org/docs/handbook/utility-types.html)
  * All types from `type-fest` package.
  * `typeof` keyword.
  * ...
* Index Signature
  ```ts
  interface Type {
    [key: string]: string
  }
  ```
* Generics will be ignored directly

#### What are Key Places?

* The names of props.

```ts
// ✅
defineProps<{
  foo: ComplexType
}>()

// ❌
defineProps<{
  [ComplexType]: string
}>()
```

* The names of emits.

```ts
interface Emits {
  (event: 'something', value: ComplexType): void // ✅
  (event: ComplexType): void // ❌
}
```

---

---
url: /features/boolean-prop.md
---
# booleanProp&#x20;

Convert `<Comp checked />` to `<Comp :checked="true" />`.

Convert `<Comp !checked />` to `<Comp :checked="false" />`.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     |        :x:         |
| Volar Plugin | :white\_check\_mark: |

## Options

```ts
interface Options {
  /**
   * @default '!'
   */
  negativePrefix?: string
}
```

## Usage

```vue twoslash
<script setup>
import type { FunctionalComponent } from 'vue'

export const Comp: FunctionalComponent<
  {
    checked: true,
    enabled: false,
  },
> = () => null
// ---cut---
// @noErrors
import Comp from './Comp.vue'
</script>

<template>
  <Comp checked !enabled />
  //             ^?
</template>
```

```vue twoslash
<script setup lang="ts">
// Comp.vue
defineProps<{
  checked: true
  enabled: false
}>()
</script>
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "booleanProp": true,
    },
  },
}
```

---

---
url: /guide/bundler-integration.md
---
# Bundler Integration&#x20;

## Installation

::: tip

Vite and Rollup are fully supported, while other bundlers have limited support.

:::

::: code-group

```bash [npm]
npm i -D vue-macros
```

```bash [yarn]
yarn add -D vue-macros
```

```bash [pnpm]
pnpm add -D vue-macros
```

:::

::: code-group

```ts [Vite]
// vite.config.ts
import Vue from '@vitejs/plugin-vue'
import VueMacros from 'vue-macros/vite'
// import VueJsx from '@vitejs/plugin-vue-jsx'
// import VueRouter from 'unplugin-vue-router/vite'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue(),
        // vueJsx: VueJsx(), // if needed
        // vueRouter: VueRouter({ // if needed
        //   extensions: ['.vue', '.setup.tsx']
        // })
      },
      // overrides plugin options
    }),
  ],
})
```

```ts [Rollup]
// rollup.config.js (Requires Rollup 3+)
import Vue from 'unplugin-vue/rollup'
import VueMacros from 'vue-macros/rollup'
// import VueRouter from 'unplugin-vue-router/rollup'

export default {
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue(),
        // vueJsx: VueJsx(), // if needed
        // vueRouter: VueRouter({ // if needed
        //   extensions: ['.vue', '.setup.tsx']
        // })
      },
      // overrides plugin options
    }),
  ],
}
```

```js [esbuild]
// esbuild.config.js
import { build } from 'esbuild'
// import VueRouter from 'unplugin-vue-router/esbuild'

build({
  plugins: [
    require('vue-macros/esbuild')({
      plugins: {
        vue: require('unplugin-vue/esbuild')(),
        // vueJsx: VueJsx(), // if needed
        // vueRouter: VueRouter({ // if needed
        //   extensions: ['.vue', '.setup.tsx']
        // })
      },
      // overrides plugin options
    }),
  ],
})
```

```js [Webpack]
// webpack.config.js (Requires Webpack 5+)
module.exports = {
  /* ... */
  plugins: [
    require('vue-macros/webpack')({
      // overrides plugin options
    }),
  ],
}
```

```js [Rspack]
// rspack.config.js
module.exports = {
  /* ... */
  plugins: [
    require('vue-macros/rspack')({
      // overrides plugin options
    }),
  ],
}
```

```js [Rsbuild]
// rsbuild.config.js
module.exports = {
  // ...
  tools: {
    rspack: {
      plugins: [
        require('vue-macros/rspack')({
          // overrides plugin options
        }),
      ],
    },
  },
}
```

```js [Vue CLI]
// vue.config.js (Requires Vue CLI 5+)
const { defineConfig } = require('@vue/cli-service')
const VueMacros = require('vue-macros/webpack')

module.exports = defineConfig({
  // ...
  // ⚠️ IMPORTANT
  parallel: false,
  configureWebpack: {
    plugins: [
      VueMacros({
        // overrides plugin options
      }),
    ],
  },
})
```

:::

## Configuration

See the [Configurations](./configurations.md) for more details.

```ts twoslash [vue-macros.config.ts]
import { defineConfig } from 'vue-macros'
export default defineConfig({
  // options
})
```

## TypeScript Support

```json {0}
// tsconfig.json
{
  "compilerOptions": {
    // ...
    "types": ["vue-macros/macros-global" /* ... */]
  }
}
```

## Volar Support

For detailed configuration, please refer to the description of the specific macro.

```jsonc [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

### Scoped Plugins

`exportExpose`, `exportProps`, and `exportRender` plugins cannot be used
at the same time unless providing a scope.

```ts twoslash [vue-macros.config.ts]
import { defineConfig } from 'vue-macros'
export default defineConfig({
  exportExpose: {
    include: ['**/export-expose/**'],
  },
  exportProps: {
    include: ['**/export-props/**'],
  },
  exportRender: {
    include: ['**/export-render/**'],
  },
})
```

***

:tada: Congratulations! You have successfully set up Vue Macros.

To learn more about the macros, please visit [All Macros](/macros/) :laughing:.

---

---
url: /macros/chain-call.md
---
# chainCall&#x20;

Extends `defineProps`, support call `withDefaults` as a chain.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    |     :question:     |
|    Vue 2     |     :question:     |
|  TypeScript  | :white\_check\_mark: |
| Volar Plugin |        :x:         |

::: tip

* `chainCall` does not support `definePropsRefs`
* To fully support TypeScript, you need to import this macro from `vue-macros/macros`.

:::

## Basic Usage

```vue
<script setup lang="ts">
const props = defineProps<{
  foo?: string
  bar?: number[]
  baz?: boolean
}>().withDefaults({
  foo: '111',
  bar: () => [1, 2, 3],
})
</script>
```

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const props = withDefaults(
  defineProps<{
    foo?: string
    bar?: number[]
    baz?: boolean
  }>(),
  {
    foo: '111',
    bar: () => [1, 2, 3],
  },
)
</script>
```

:::

Also support [props destructuring](../features/reactivity-transform.md) and JSX:

```vue
<script setup lang="ts">
const { foo } = defineProps<{ foo: string }>().withDefaults({
  foo: '111',
})
</script>
```

## TypeScript

To fully support TypeScript, you need to import this macro from `vue-macros/macros` with specific syntax.

```vue twoslash
<script setup lang="ts">
import { defineProps } from 'vue-macros/macros' with { type: 'macro' }

defineProps<{
  /* ... */
}>().withDefaults({
  /* ... */
})
// ✅ type safe
</script>
```

Works without import assertion, but tsc will report an error:

```ts twoslash
// @errors: 2339
defineProps<{
  /* ... */
}>().withDefaults({
  /* ... */
})
```

---

---
url: /guide/configurations.md
---
# Configurations

## Plugin Options

All features are enabled by default except the following.

#### Disabled by Default

* `exportExpose`
* `exportProps`
* `exportRender`
* `setupSFC`
* `booleanProp`
* `shortBind`
* `defineStyleX`

#### Disabled by Default when Vue >= 3.3

* `defineOptions`
* `defineSlots`
* `hoistStatic`
* `shortEmits`

You can re-enable them by setting the option to `true`.

```ts twoslash [vue-macros.config.(ts,js,json)]
import { defineConfig } from 'vue-macros'
export default defineConfig({
  root: '/your-project-path',

  /**
   * Vue version, 2 or 3.
   *
   * optional, detecting automatically.
   */
  version: 3,

  /** Defaults to true */
  defineModels: {
    // ...
  },

  // Enable features
  defineOptions: true,

  // Disable features
  hoistStatic: false,

  // ... more features
})
```

Refer to the macros and features page for available options.

---

---
url: /macros/define-emit.md
---
# defineEmit&#x20;

Declare single emit one by one using `defineEmit`.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     | :white\_check\_mark: |
|  TypeScript  | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

::: warning

`defineEmit` can not be used with `defineEmits` at same time

:::

## API Reference

```ts
defineEmit<T>(emitName)
defineEmit<T>(emitName, validator)

// emitName parameter can be optional,
// and will be inferred from variable name
const emitName = defineEmit<T>()
```

## Basic Usage

```vue twoslash
<script setup>
// Declare emit
const increment = defineEmit('increment')
// Infer emit name from variable name
const change = defineEmit()
// emit event
increment()
</script>
```

## With Validation

```vue twoslash
<script setup>
// Declare event with validation
const increment = defineEmit('increment', (value) => value < 20)
</script>
```

## TypeScript

```vue twoslash
<script setup lang="ts">
const increment = defineEmit('increment', (value: number) => value < 20)
const decrement = defineEmit<[value: number]>()

increment(2) // pass
// @errors: 2345
increment('2') // TS type error
</script>
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "defineEmit": true,
    },
  },
}
```

---

---
url: /volar/define-generic.md
---
# defineGeneric&#x20;

Declare single generic one by one using `DefineGeneric`.

> Especially useful for `setup-sfc`.

|   Features   |     Supported      |
| :----------: | :----------------: |
| Volar Plugin | :white\_check\_mark: |

## Basic Usage

::: code-group

```vue [App.vue] twoslash
<script setup lang="ts">
// @errors: 2322
defineOptions({
  name: 'App',
})

type T = DefineGeneric<number>

defineProps<{
  foo: T
}>()
</script>

<template>
  <App foo="1" />
</template>
```

:::

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-models.md
---
# defineModels&#x20;

Declaring and mutate `v-model` props as the same as normal variable using the `defineModels`.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

## Options

```ts
VueMacros({
  defineModels: {
    /**
     * Unified mode, only works for Vue 2
     *
     * Converts `modelValue` to `value`
     */
    unified: false,
  },
})
```

## Basic Usage

Requires [`@vueuse/core`](https://www.npmjs.com/package/@vueuse/core), install it by yourself before using.

```vue twoslash
<script setup lang="ts">
const { modelValue, count } = defineModels<{
  modelValue: string
  count: number
}>()

console.log(modelValue.value)
modelValue.value = 'newValue'
</script>
```

::: warning ❌ Object declaring is not supported.

```vue
<script setup lang="ts">
const { modelValue } = defineModels({
  modelValue: String,
})
</script>
```

:::

## With Model Options

```vue twoslash 3-6
<script setup lang="ts">
const { modelValue } = defineModels<{
  modelValue: ModelOptions<
    string,
    { defaultValue: 'something'; deep: true; passive: true }
  >
}>()
</script>
```

## With Reactivity Transform

::: warning

Assignment expression is only supported in `<script setup>` block. In other words invalid in `<template>`.

:::

[`@vueuse/core`](https://www.npmjs.com/package/@vueuse/core) is not required.

```vue twoslash {7-9}
<script setup lang="ts">
let { modelValue, count } = $defineModels<{
  modelValue: string
  count: number
}>()

console.log(modelValue)
modelValue = 'newValue'
count++
</script>
```

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const { modelValue, count } = defineProps<{
  modelValue: string
  count: number
}>()

const emit = defineEmits<{
  (evt: 'update:modelValue', value: string): void
  (evt: 'update:count', value: number): void
}>()

console.log(modelValue)
emit('update:modelValue', 'newValue')
emit('update:count', count + 1)
</script>
```

:::

## Volar Configuration

```jsonc {4,6-9} [tsconfig.json]
{
  "vueCompilerOptions": {
    "target": 3, // or 2.7 for Vue 2
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "defineModels": {
        // Only works when target is 2.7.
        "unified": true,
      },
    },
  },
}
```

---

---
url: /macros/define-options.md
---
# defineOptions&#x20;

Options API can be declared using the `defineOptions` in `<script setup>`, specifically to be able to set `name`, `props`, `emits`, and `render` inside of one function.

For Vue >= 3.3, this feature will be turned off by default.

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Nuxt 3   | :white\_check\_mark: |
|   Vue 2    | :white\_check\_mark: |
| TypeScript | :white\_check\_mark: |

## Installation Standalone Version

if you need `defineOptions` feature only, the standalone version is more appropriate for you.

### Installation

::: code-group

```bash [npm]
npm i -D unplugin-vue-define-options @vue-macros/volar
```

```bash [yarn]
yarn add -D unplugin-vue-define-options @vue-macros/volar
```

```bash [pnpm]
pnpm add -D unplugin-vue-define-options @vue-macros/volar
```

:::

::: code-group

```ts [Vite]
// vite.config.ts
import DefineOptions from 'unplugin-vue-define-options/vite'

export default defineConfig({
  plugins: [DefineOptions()],
})
```

```ts [Rollup]
// rollup.config.js
import DefineOptions from 'unplugin-vue-define-options/rollup'

export default {
  plugins: [DefineOptions()],
}
```

```js [esbuild]
// esbuild.config.js
import { build } from 'esbuild'

build({
  plugins: [require('unplugin-vue-define-options/esbuild')()],
})
```

```js [Webpack]
// webpack.config.js
module.exports = {
  /* ... */
  plugins: [require('unplugin-vue-define-options/webpack')()],
}
```

:::

### TypeScript Support

```json [tsconfig.json]
{
  "compilerOptions": {
    // ...
    "types": ["unplugin-vue-define-options/macros-global" /* ... */]
  }
}
```

## Basic Usage

```vue twoslash {3-4}
<script setup lang="ts">
defineOptions({
  name: 'Foo',
  inheritAttrs: false,
})

defineProps<{
  foo: number
}>()
</script>

<template>
  <Foo :foo="1" />
</template>
```

::: details Compiled Code

```vue twoslash
<script lang="ts">
export default {
  name: 'Foo',
  inheritAttrs: false,
}
</script>

<script setup lang="ts">
defineProps<{
  foo: number
}>()
</script>

<template>
  <Foo :foo="1" />
</template>
```

:::

## JSX in `<script setup>`

```vue twoslash {3-5}
<script setup lang="tsx">
defineOptions({
  render() {
    return <h1>Hello World</h1>
  },
})
</script>
```

::: details Compiled Code

```vue
<script lang="tsx">
export default {
  render() {
    return <h1>Hello World</h1>
  },
}
</script>
```

:::

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-prop.md
---
# defineProp&#x20;

Declare single prop one by one using `defineProp`.

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|       Nuxt 3       | :white\_check\_mark: |
|       Vue 2        | :white\_check\_mark: |
| TypeScript / Volar | :white\_check\_mark: |

::: warning

`defineProp` can not be used in the same file as type-declared `defineProps`.

:::

## Configuration

```ts
VueMacros({
  defineProp: {
    /**
     * 'kevinEdition' | 'johnsonEdition'
     * @default 'kevinEdition'
     */
    edition: 'kevinEdition',
  },
})
```

## Kevin's Edition (Default)

### API Reference

```ts
defineProp<T>(propName)
defineProp<T>(propName, options)

// propName parameter can be optional,
// and will be inferred from variable name
const propName = defineProp<T>()
```

### Basic Usage

```vue twoslash
<script setup lang="ts">
// Declare prop
const count = defineProp('count')

// Infer prop name from variable name
const value = defineProp()

// access prop value
console.log(count.value)
</script>
```

### With Options

```vue twoslash
<script setup lang="ts">
// Declare prop with options
const count = defineProp('count', {
  type: Number,
  required: true,
  default: 0,
  validator: (value: number) => value < 20,
})
</script>
```

### TypeScript

```vue twoslash
<script setup lang="ts">
// Declare prop of type number and infer prop name from variable name
const count = defineProp<number>()
count.value

// Declare prop of TS type boolean with default value
const disabled = defineProp<boolean>('disabled', { default: true })
disabled.value
</script>
```

### With Reactivity Transform

```vue twoslash
<script setup lang="ts">
const foo = $defineProp<string>('foo')

const bar = $(defineProp('bar', { default: 'bar' }))
</script>
```

## Johnson's Edition

### API Reference

```ts
// the prop name will be inferred from variable name
const propName = defineProp<T>()
const propName = defineProp<T>(defaultValue)
const propName = defineProp<T>(defaultValue, required)
const propName = defineProp<T>(defaultValue, required, rest)
```

### Basic Usage

```vue
<script setup lang="ts">
// declare prop `count` with default value `0`
const count = defineProp(0)

// declare required prop `disabled`
const disabled = defineProp(undefined, true)

// access prop value
console.log(count.value, disabled.value)
</script>
```

### With Options

```vue
<script setup lang="ts">
// Declare prop with options
const count = defineProp(0, false, {
  type: Number,
  validator: (value: number) => value < 20,
})
</script>
```

### TypeScript

```vue
<script setup lang="ts">
const count = defineProp<number>()
count.value

// Declare prop of TS type boolean with default value
const disabled = defineProp<boolean>(true)
disabled.value
</script>
```

### With Reactivity Transform

```vue
<script setup lang="ts">
const foo = $defineProp<number>()

const bar = $(defineProp(0, true))
</script>
```

### Volar Configuration

```jsonc {3,7} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "defineProp": {
        // "kevinEdition" | "johnsonEdition"
        "edition": "kevinEdition",
      },
    },
  },
}
```

---

---
url: /macros/define-props.md
---
# defineProps&#x20;

Correct types of destructured props using `$defineProps`.

See also [Vue issue](https://github.com/vuejs/core/issues/6876), [Reactivity Transform RFC](https://github.com/vuejs/rfcs/blob/reactivity-transform/active-rfcs/0000-reactivity-transform.md#defineprops-destructure-details).

|         Features          |     Supported      |
| :-----------------------: | :----------------: |
|           Vue 3           | :white\_check\_mark: |
|          Nuxt 3           | :white\_check\_mark: |
|           Vue 2           | :white\_check\_mark: |
| TypeScript / Volar Plugin | :white\_check\_mark: |

::: warning

[Reactivity Transform](../features/reactivity-transform.md) is required. You should enable it first.

:::

## Basic Usage

```vue twoslash
<script setup lang="ts">
const { foo } = $defineProps<{
  //     ^?
  foo: string[]
}>()

const fooRef = $(foo)
//     ^?
</script>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-props-refs.md
---
# definePropsRefs&#x20;

Returns refs from `defineProps` instead of a reactive object. It can be destructured without losing reactivity.

`toRefs(defineProps())` => `definePropsRefs()`

|         Features          |     Supported      |
| :-----------------------: | :----------------: |
|           Vue 3           | :white\_check\_mark: |
|          Nuxt 3           | :white\_check\_mark: |
|           Vue 2           | :white\_check\_mark: |
| TypeScript / Volar Plugin | :white\_check\_mark: |

## Basic Usage

```vue twoslash {2-3,8}
<script setup lang="ts">
// ✅ won't lose reactivity with destructuring
const { foo, bar } = definePropsRefs<{
  foo: string
  bar: number
}>()

console.log(foo.value, bar.value)
//           ^?
</script>
```

## With Default Value

```vue twoslash {2-3,8}
<script setup lang="ts">
import { withDefaults } from 'vue-macros/macros' with { type: 'macro' }

const { foo } = withDefaults(
  definePropsRefs<{
    foo?: string
  }>(),
  { foo: 'test' },
)

console.log(foo.value)
//           ^?
</script>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-render.md
---
# defineRender&#x20;

Defining render function in `<script setup>` using the `defineRender`.

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Nuxt 3   | :white\_check\_mark: |
|   Vue 2    | :white\_check\_mark: |
| TypeScript | :white\_check\_mark: |

We need more feedback on [RFC Discussion](https://github.com/vuejs/rfcs/discussions/585)!

## Basic Usage

```vue twoslash
<script setup lang="tsx">
// JSX passed directly
defineRender(
  <div>
    <span>Hello</span>
  </div>,
)

// Or using render function
defineRender(() => {
  return (
    <div>
      <h1>Hello World</h1>
    </div>
  )
})
</script>
```

---

---
url: /macros/define-slots.md
---
# defineSlots&#x20;

Declaring type of SFC slots in `<script setup>` using the `defineSlots`.

For Vue >= 3.3, this feature will be turned off by default.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |
|    Vue 2     |        :x:         |

## Basic Usage

### Short Syntax

```vue twoslash
<script setup lang="ts">
defineSlots<{
  // slot name
  title: {
    // scoped slot
    foo: 'bar' | boolean
  }
}>()
</script>
```

### Full Syntax (Official Version)

```vue twoslash
<script setup lang="ts">
defineSlots<{
  title: (scope: { text: string }) => any
}>()
</script>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-stylex.md
---
# defineStyleX&#x20;

Define and consume [StyleX](https://stylexjs.com/) styles in `<script setup>`.

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|       Nuxt 3       | :white\_check\_mark: |
| TypeScript / Volar | :white\_check\_mark: |
|       Vue 2        | :white\_check\_mark: |

## Setup

To use StyleX, you should install and configure StyleX first. The steps could change, you may want to check the [official document](https://stylexjs.com/) and the [document of StyleX bundler integrations](https://stylexjs.com/docs/learn/ecosystem/#third-party-bundler-integrations) for the latest information.

### Vite

```sh
pnpm add @stylexjs/stylex @stylex-extend/core @stylex-extend/vite -D
```

```ts [vite.config.ts] {1,13}
import { stylex } from '@stylex-extend/vite'
import Vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
import VueMacros from 'vue-macros/vite'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue(),
      },
    }),
    stylex(), // Must be placed after Vue Macros
  ],
})
```

```ts [main.ts] {2}
// import StyleX stylesheet, according to https://nonzzz.github.io/stylex-extend/integrations/vite
import 'virtual:stylex.css'
```

## Basic Usage

```vue [App.vue] twoslash
<script setup lang="ts">
const styles = defineStyleX({
  red: { color: 'red' },
})

// ...
// ---cut-start---
declare const vStylex: any
// ---cut-end---
</script>

<template>
  <p v-stylex="styles.red">Red</p>
</template>
```

:::details Compiled Code (with some simplifications)

```vue [App.vue] twoslash
<script lang="ts">
const styles = _stylex_create({
  red: { color: 'red' },
})
</script>

<script setup lang="ts">
import {
  create as _stylex_create,
  props as _stylex_props,
} from '@stylexjs/stylex'
// virtual module to provide runtime code
// ---cut-start---
// @ts-ignore
// ---cut-end---
import stylex_attrs from '/vue-macros/define-stylex/stylex-attrs'

// ...
</script>

<template>
  <p v-bind="stylex_attrs(_stylex_props(styles.red))">Red</p>
</template>
```

:::

## Conditional Styles

Optional and multiple rules are supported.

```vue [App.vue] twoslash
<script setup lang="ts">
defineProps<{ bold?: boolean }>()

const styles = defineStyleX({
  red: { color: 'red' },
  bold: { fontWeight: 'bold' },
})
// ---cut-start---
declare const vStylex: any
// ---cut-end---
</script>

<template>
  <span v-stylex="(styles.red, bold && styles.bold)">Red</span>
</template>
```

:::details Compiled Code (with some simplifications)

```vue [App.vue] twoslash
<script lang="ts">
const styles = _stylex_create({
  red: { color: 'red' },
  bold: { fontWeight: 'bold' },
})
</script>

<script setup lang="ts">
import {
  create as _stylex_create,
  props as _stylex_props,
} from '@stylexjs/stylex'
// ---cut-start---
// @ts-ignore
// ---cut-end---
import stylex_attrs from '/vue-macros/define-stylex/stylex-attrs'

defineProps<{ bold?: boolean }>()
</script>

<template>
  <span v-bind="stylex_attrs(_stylex_props(styles.red, bold && styles.bold))"
    >Red</span
  >
</template>
```

:::

---

---
url: /features/export-expose.md
---
# exportExpose&#x20;

Transform export statement as `defineExpose` params in Vue SFC `script-setup`.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    |         ?          |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

## Usage

Support these syntaxes:

* local variable/function/class
* export with alias
* export from other file
* namespace export
* rename export

### 1. local variable/function/class

```vue twoslash
<script setup lang="ts">
export const foo: string = 'foo'
export const bar = 10
export let baz: string | undefined
export var qux = fn()
// @errors: 2448 2454 2695
export const { a, b, c } = { a: 1, b: 2, c: 3 }

export function fn() {}
export class A {}
</script>
```

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const foo: string = 'foo'
const bar = 10
let baz: string | undefined
const qux = fn()
const { a, b, c } = { a: 1, b: 2, c: 3 }

function fn() {}
class A {}

defineExpose({
  foo,
  bar,
  baz,
  qux,
  a,
  b,
  c,
  fn,
  A,
})
</script>
```

:::

### 2. export with alias

```vue twoslash
<script setup lang="ts">
const foo = ''

export { foo as foo1 }
</script>
```

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const foo = 'foo'

defineExpose({
  foo1: foo,
})
</script>
```

:::

### 3. export from other file

::: code-group

```vue [App.vue] twoslash
<script setup lang="ts">
// #region export-file
const foo = 'foo'
type Foo = string

export { foo, type Foo }
// #endregion export-file
// ---cut---
// @noErrors
export { foo as bar, foo, type Foo } from './types'
</script>
```

<<< ./export-expose.md#export-file{ts} \[types.ts]

:::

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const __MACROS_expose_0 = 'foo'
const __MACROS_expose_1 = 'foo'
type Foo = string
// ---cut---
// @noErrors
import {
  foo as __MACROS_expose_0,
  foo as __MACROS_expose_1,
  type Foo,
} from './types'
defineExpose({
  foo: __MACROS_expose_0,
  bar: __MACROS_expose_1,
})
</script>
```

:::

### 4. namespace export

::: code-group

```vue [App.vue] twoslash
<script setup lang="ts">
const foo = { foo: 'foo' }
// ---cut---
// @noErrors
export * as foo from './types'
</script>
```

```ts [types.ts]
export const foo = 'foo'
```

:::

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const __MACROS_expose_0 = {
  foo: 'foo',
}
// ---cut---
// @noErrors
import * as __MACROS_expose_0 from './types'
defineExpose({
  foo: __MACROS_expose_0,
})
</script>
```

:::

### 5. rename export

```vue
<script setup lang="ts">
const foo = 1
const bar = 1

export { foo } from './types'
export * as bar from './types'
</script>
```

::: details Compiled Code

```vue
<script setup lang="ts">
import { foo as __MACROS_expose_0 } from './types'
import * as __MACROS_expose_1 from './types'

const foo = 1
const bar = 1
defineExpose({
  foo: __MACROS_expose_0,
  bar: __MACROS_expose_1,
})
</script>
```

:::

## Limitations

Currently does't support these following cases:

```ts
// 1. export all ❌
export * from '../types'

// 2. export default ❌
const a = 'a'
export default a
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "exportExpose": true,
    },
  },
}
```

---

---
url: /features/export-props.md
---
# exportProps&#x20;

[Svelte-like Declaring props](https://svelte.dev/docs#component-format-script-1-export-creates-a-component-prop) for Vue.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    |     :question:     |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

## Pre-requisite

[Reactivity Transform](./reactivity-transform.md) is required to use this feature, but it is enabled by default in Vue Macros.

`export let` will be changed to `defineModel`, which is supported in Vue 3.4+.

## Usage

Using export syntax to declare props.

```vue twoslash
<script setup lang="ts">
export let foo: string
export const bar: number = 1 // with default value
</script>
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "exportProps": true,
    },
  },
}
```

---

---
url: /features/export-render.md
---
# exportRender&#x20;

Transform the default export statement, in `<script setup>` of Vue SFC, as a component render function.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    |     :question:     |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

::: tip

This feature depends on `defineRender`, and make sure `defineRender` is not disabled.

:::

## Usage

```vue
<script setup lang="tsx">
// JSX passed directly
export default <div>ok</div>

// Or using render function
export default () => <div>ok</div>
</script>
```

## Volar Configuration

```jsonc {3,7} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "exportRender": true,
    },
  },
}
```

---

---
url: /guide/getting-started.md
---
# Getting Started

Vue Macros is a library that implements unofficial proposals and ideas for Vue,
exploring and extending its features and syntax.

We assume you are already familiar with the basic usages of Vue before you continue.

## Requirements

* Node.js `>= v20.19.0`.
* Vue `>= v2.7` or Vue `>= v3.0`.
  * Some features need Vue `>= v3.2.25`.
* VSCode extension [Vue - Official](https://marketplace.visualstudio.com/items?itemName=Vue.volar) and `vue-tsc` are v{{ version }}
  * Vue Macros will continue to adapt to the latest version as soon as possible, older versions may not be supported.

::: warning
WebStorm is not supported.
:::

## Creating a Vue Macros Project

### Installation

::: code-group

```bash [npm]
npm i -g @vue-macros/cli
```

```bash [yarn]
yarn global add @vue-macros/cli
```

```bash [pnpm]
pnpm add -g @vue-macros/cli
```

:::

This command will install [@vue-macros/cli](https://github.com/vue-macros/vue-macros-cli), the official Vue Macros scaffolding tool.

### Initialization

::: code-group

```bash [npm]
npm create vite@latest my-vue-macros -- --template vue-ts
cd my-vue-macros
vue-macros init
```

```bash [yarn]
yarn create vite my-vue-macros --template vue-ts
cd my-vue-macros
vue-macros init
```

```bash [pnpm]
pnpm create vite my-vue-macros --template vue-ts
cd my-vue-macros
vue-macros init
```

You will be presented with prompts for several optional experimental features.

:::

## Templates

* [Vite](https://github.com/vue-macros/vite)
* [Nuxt](https://github.com/vue-macros/nuxt)
* [Rsbuild](https://github.com/vue-macros/vue3-rsbuild)

🌟 More templates are welcome!

## Nuxt Integration

If you're using [Nuxt](https://nuxt.com/), read the [Nuxt Integration](./nuxt-integration.md).

## Bundler Integrations

If you're using [Vite](https://vitejs.dev/), [Rollup](https://rollupjs.org/), [esbuild](https://esbuild.github.io/), [Webpack](https://webpack.js.org/), or [Rspack](https://www.rspack.dev/), read the [Bundler Integration](./bundler-integration.md).

---

---
url: /features/hoist-static.md
---
# hoistStatic&#x20;

With enabling `hoistStatic`, constants declared in macros of `<script setup>` can be referenced.

For Vue >= 3.3, this feature will be turned off by default.

| Features |     Supported      |
| :------: | :----------------: |
|  Vue 3   | :white\_check\_mark: |
|  Nuxt 3  | :white\_check\_mark: |
|  Vue 2   | :white\_check\_mark: |

## Basic Usage

```vue twoslash
<script setup lang="ts">
const name = 'AppFoo'
defineOptions({
  name,
})
</script>
```

::: details Compiled Code

```vue
<script lang="ts">
const name = 'AppFoo'
export default {
  name,
}
</script>
```

:::

## Magic Comments

```vue
<script setup lang="ts">
// A value that's even not a constant
const name = /* hoist-static */ fn()
defineOptions({
  name,
})
</script>
```

::: details Compiled Code

```vue
<script lang="ts">
const name = fn()
export default {
  name,
}
</script>
```

:::

---

---
url: /features/jsx-directive.md
---
# jsxDirective&#x20;

Vue built-in directives for JSX.

|  Directive  |       Vue 3        |       Vue 2        |       Volar        |
| :---------: | :----------------: | :----------------: | :----------------: |
|   `v-if`    | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
| `v-else-if` | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|  `v-else`   | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|   `v-for`   | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|   `v-on`    | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|  `v-slot`   | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|  `v-html`   | :white\_check\_mark: | :white\_check\_mark: |         /          |
|  `v-once`   | :white\_check\_mark: |        :x:         |         /          |
|  `v-memo`   | :white\_check\_mark: |        :x:         |         /          |

## Options

```ts
interface Options {
  /**
   * @default 'v-'
   */
  prefix?: string
  /**
   * @default 'vue'
   */
  lib?: 'vue' | 'react' | 'preact' | 'solid' | string
}
```

## Usage

### `v-if`, `v-else-if`, `v-else`

```vue twoslash
<script setup lang="tsx">
const { foo } = defineProps<{
  foo: number
}>()

// ---cut-start---
// prettier-ignore
// ---cut-end---
export default () => (
  <>
    <div v-if={foo === 0}>{foo}</div>

    <div v-else-if={foo === 1}>{foo}</div>
    //                          ^?

    <div v-else>{foo}</div>
    //           ^?
  </>
)
</script>
```

### `v-for`

```vue twoslash
<script setup lang="tsx">
export default () => (
  <div v-for={(item, index) in 4} key={index}>
    {item}
  </div>
)
</script>
```

### `v-slot`

::: code-group

```vue [App.vue] twoslash
<script lang="tsx" setup>
// #region v-slot
import type { FunctionalComponent } from 'vue'

export const Comp: FunctionalComponent<
  {},
  {},
  {
    default: () => any
    slot: (scope: { bar: number }) => any
    slots: (scope: { baz: boolean }) => any
  }
> = () => <div />
// #endregion v-slot
// ---cut---
// @noErrors
import { Comp } from './Comp.tsx'

// ---cut-start---
// prettier-ignore
// ---cut-end---
export default () => (
  <Comp>
    default slot...
    <template v-slot:slot={{ bar }}>
      //              ^|
      {bar}
    </template>
  </Comp>
)
</script>
```

<<< ./jsx-directive.md#v-slot{tsx} \[Child.tsx]

:::

### `v-on`

::: warning

`v-on` only supports binding to an object of event / listener pairs without an argument.

:::

```tsx
<form v-on={{ submit }} />
```

## Dynamic Arguments

It is also possible to use a variable in a directive argument by wrapping it with a pair of `


  
  
  
  
  vue-macros.dev | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


  :

`v-model`

::: code-group

```vue [App.vue] twoslash
<script setup lang="tsx">
// ---cut-start---
// #region v-model
import { ref, type FunctionalComponent } from 'vue'

export const Comp: FunctionalComponent<
  {
    model: string
    models: string[]
  },
  {
    'update:model': [value: string]
    'update:models': [value: string[]]
  }
> = () => <div />
// #endregion v-model
// ---cut-end---
// @noErrors
import { Comp } from './Comp.tsx'

const name = ref('model')
const model = defineModel<string>()

export default () => (
  <Comp
    v-model:$name$={model.value}
    v-model:model={model.value}
    //       ^|
  />
)
</script>
```

<<< ./jsx-directive.md#v-model{tsx} \[Comp.tsx]

:::

`v-slot`

::: code-group

```vue [App.vue] twoslash
<script setup lang="tsx">
// ---cut-start---
// #region v-slot-dynamic
import type { FunctionalComponent } from 'vue'

export const Comp: FunctionalComponent<
  {},
  {},
  {
    default: (scope: { foo: string }) => any
    title: (scope: { bar: number }) => any
  }
> = () => <div />
// #endregion v-slot-dynamic
// ---cut-end---
// @noErrors
import { Comp } from './Comp.tsx'

const slots = defineSlots<{
  default: (scope: { foo: string }) => any
  title: (scope: { bar: number }) => any
}>()

// ---cut-start---
// prettier-ignore
// ---cut-end---
export default () => (
  <Comp>
    <template v-for={(Slot, name) in slots} v-slot:$name$={scope}>
      //                                             ^?
      <Slot {...scope} />
    </template>
  </Comp>
)
</script>
```

<<< ./jsx-directive.md#v-slot-dynamic{tsx} \[Comp.tsx]

:::

## Modifiers

Modifiers are special postfixes denoted by a `_`, which indicate that a directive should be bound in some special way.

```tsx
<form onSubmit_prevent>
  <input v-model_number={value} />
</form>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /volar/jsx-ref.md
---
# jsxRef&#x20;

Automatically infer type for `useRef`.

| Features |     Supported      |
| :------: | :----------------: |
|  Volar   | :white\_check\_mark: |

## Setup Auto Import

::: code-group

```ts [vite.config.ts]
import AutoImport from 'unplugin-auto-import/vite'

export default defineConfig({
  plugins: [
    AutoImport({
      imports: [
        {
          from: 'vue',
          imports: [['shallowRef', 'useRef']],
        },
      ],
    }),
  ],
})
```

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  imports: {
    presets: [
      {
        from: 'vue',
        imports: [['shallowRef', 'useRef']],
      },
    ],
  },
})
```

:::

## Basic Usage

::: code-group

```vue [App.vue] twoslash
<script lang="tsx">
// #region comp
import { defineComponent } from 'vue'

export const Comp = defineComponent({
  setup() {
    return { foo: 1 }
  },
})
// #endregion comp
// ---cut---
import { useRef } from 'vue-macros/runtime'
// Or import { shallowRef as useRef } from 'vue'
// @noErrors
import { Comp } from './Comp.ts'

export default defineComponent(() => {
  const comp = useRef()
  comp.value?.foo
  //           ^?

  return () => (
    <>
      <Comp ref={comp} />
    </>
  )
})
</script>
```

<<< ./jsx-ref.md#comp{ts} \[Comp.ts]

:::

## Volar Configuration

```jsonc [tsconfig.json] {3,6}
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "jsxRef": {
        "alias": ["useRef"],
      },
    },
  },
}
```

---

---
url: /guide/migration-v3.md
---
# Migration from v2 to v3

## Unified Version Management

Initially, we used [`changesets`](https://github.com/changesets/changesets) to
manage the versions of all packages in the monorepo. However, after two years of experimentation,
we decided to adopt a single-version strategy in v3,
where all sub-packages share the same version number, similar to Vue and Babel.
This decision stemmed from our observation that when a sub-package underwent a major change or minor update,
the version number of the main package did not adequately reflect these changes.

For example, when `@vue-macros/define-prop` introduced a breaking change,
how should `unplugin-vue-macros` release a new version?
Should it be a minor or a patch release? When users updated `unplugin-vue-macros`,
they couldn’t easily determine whether the update was due to changes in `@vue-macros/define-prop`.

Therefore, after Anthony proposed [Epoch Semantic Versioning](https://antfu.me/posts/epoch-semver),
we decided to adopt a more frequent major version update strategy,
with all packages sharing the same version number and maintaining a single unified changelog.

## Main Package Rename

We have renamed the main package from `unplugin-vue-macros` to **`vue-macros`**.
After the official release of v3, `unplugin-vue-macros` will be marked as deprecated.

As a result, you will need to update your `package.json` and the import statements for Vue Macros:

```diff
 // package.json
 {
   "devDependencies": {
-    "unplugin-vue-macros": "^2.14.5"
+    "vue-macros": "^3.0.0"
   }
 }
```

```diff
- import { $ref } from 'unplugin-vue-macros/macros'
+ import { $ref } from 'vue-macros/macros'

- import VueMacros from 'unplugin-vue-macros/vite'
+ import VueMacros from 'vue-macros/vite'
```

## Dropping Vue 2 Support

Vue 2 reached its end of life (EOL) at the end of 2023, so we have decided to drop support for Vue 2 in v3.
If you are still using Vue 2, we recommend continuing with v2 or
considering our [paid support plan](https://github.com/vue-macros/vue-macros/issues/373).

## Node.js Compatibility Changes

In v3, we have dropped support for Node.js versions below 20.19.
This means the minimum Node.js version requirement for v3 is `20.19.0`.
Additionally, we have removed CommonJS (CJS) outputs and now only provide ECMAScript modules (ESM).

## Dropping Webpack 4 Support

Since Webpack 4 cannot run in Node.js 18 or later environments,
we have also dropped support for Webpack 4 and Vue CLI 4.
We recommend upgrading to modern build tools like Vite or Rspack.

---

---
url: /features/named-template.md
---
# namedTemplate&#x20;

::: warning

Not actively maintained now. Try [createReusableTemplate](https://vueuse.org/core/createReusableTemplate/) instead.

:::

With enabling `namedTemplate`, `<template>` can be referenced like a variable.

Sometimes we need to reverse the order of the very simple components, and don't want to give the features of Vue template up and use JSX/TSX. Then this feature is much helpful.

If you support this feature, you can go to [the discussion](https://github.com/vuejs/core/discussions/6898) and hit like :+1: or comment.

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|      Vue 3.3       |        :x:         |
|       Nuxt 3       |        :x:         |
|       Vue 2        |        :x:         |
| TypeScript / Volar |        :x:         |

## Basic Usage

```vue {5-7,10-12,16-18}
<script setup>
const pager = 'top'
</script>

<template name="pager">
  <span>This is pager</span>
</template>

<template>
  <template v-if="pager === 'top'">
    <template is="pager" />
  </template>

  <span>Here is data table</span>

  <template v-if="pager === 'bottom'">
    <template is="pager" />
  </template>
</template>
```

## Known Usage

* TypeScript / Volar support is not yet completed.

---

---
url: /features/reactivity-transform.md
---
# Reactivity Transform&#x20;

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|       Nuxt 3       | :white\_check\_mark: |
|       Vue 2        | :white\_check\_mark: |
| TypeScript / Volar | :white\_check\_mark: |

## Installation Standalone Version

if you need Reactivity Transform feature only, the standalone version is more appropriate for you.

### Installation

::: code-group

```bash [npm]
npm i -D @vue-macros/reactivity-transform
```

```bash [yarn]
yarn add -D @vue-macros/reactivity-transform
```

```bash [pnpm]
pnpm add -D @vue-macros/reactivity-transform
```

:::

::: code-group

```ts [Vite]
// vite.config.ts
import ReactivityTransform from '@vue-macros/reactivity-transform/vite'

export default defineConfig({
  plugins: [ReactivityTransform()],
})
```

```ts [Rollup]
// rollup.config.js
import ReactivityTransform from '@vue-macros/reactivity-transform/rollup'

export default {
  plugins: [ReactivityTransform()],
}
```

```js [esbuild]
// esbuild.config.js
import { build } from 'esbuild'

build({
  plugins: [require('@vue-macros/reactivity-transform/esbuild')()],
})
```

```js [Webpack]
// webpack.config.js
module.exports = {
  /* ... */
  plugins: [require('@vue-macros/reactivity-transform/webpack')()],
}
```

:::

### TypeScript Support

```json [tsconfig.json]
{
  "compilerOptions": {
    // ...
    "types": ["@vue-macros/reactivity-transform/macros-global" /* ... */]
  }
}
```

## Refs vs. Reactive Variables {#refs-vs-reactive-variables}

Ever since the introduction of the Composition API, one of the primary unresolved questions is the use of refs vs. reactive objects. It's easy to lose reactivity when destructuring reactive objects, while it can be cumbersome to use `.value` everywhere when using refs. Also, `.value` is easy to miss if not using a type system.

Reactivity Transform is a compile-time transform that allows us to write code like this:

```vue twoslash
<script setup>
let count = $ref(0)

console.log(count)

function increment() {
  count++
}
</script>

<template>
  <button @click="increment">{{ count }}</button>
</template>
```

The `$ref()` method here is a **compile-time macro**: it is not an actual method that will be called at runtime. Instead, the Vue compiler uses it as a hint to treat the resulting `count` variable as a **reactive variable.**

Reactive variables can be accessed and re-assigned just like normal variables, but these operations are compiled into refs with `.value`. For example, the `<script>` part of the above component is compiled into:

```js{5,8} twoslash
import { ref } from 'vue'

let count = ref(0)

console.log(count.value)

function increment() {
  count.value++
}
```

Every reactivity API that returns refs will have a `


  
  
  
  
  vue-macros.dev | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


  -prefixed macro equivalent. These APIs include:

* [`ref`](https://vuejs.org/api/reactivity-core#ref) -> `$ref`
* [`computed`](https://vuejs.org/api/reactivity-core#computed) -> `$computed`
* [`shallowRef`](https://vuejs.org/api/reactivity-advanced#shallowref) -> `$shallowRef`
* [`customRef`](https://vuejs.org/api/reactivity-advanced#customref) -> `$customRef`
* [`toRef`](https://vuejs.org/api/reactivity-utilities#toref) -> `$toRef`

These macros are globally available and do not need to be imported when Reactivity Transform is enabled, but you can optionally import them from `vue-macros/macros` or `@vue-macros/reactivity-transform/macros-global` if you want to be more explicit:

```js twoslash
import { $ref } from 'vue-macros/macros'
// for standalone version:
// import { $ref } from '@vue-macros/reactivity-transform/macros-global'

const count = $ref(0)
```

## Destructuring with `$()` {#destructuring-with}

It is common for a composition function to return an object of refs, and use destructuring to retrieve these refs. For this purpose, reactivity transform provides the **`$()`** macro:

```js twoslash
import { ref } from 'vue'
function useMouse() {
  return {
    x: ref(0),
    y: ref(0),
  }
}
// ---cut---
const { x, y } = $(useMouse())

console.log(x, y)
```

Compiled output:

```js twoslash
import { ref, toRef } from 'vue'
function useMouse() {
  return {
    x: ref(0),
    y: ref(0),
  }
}
// ---cut---
const __temp = useMouse()
const x = toRef(__temp, 'x')
const y = toRef(__temp, 'y')

console.log(x.value, y.value)
```

Note that if `x` is already a ref, `toRef(__temp, 'x')` will simply return it as-is and no additional ref will be created. If a destructured value is not a ref (e.g. a function), it will still work - the value will be wrapped in a ref so the rest of the code works as expected.

`$()` destructure works on both reactive objects **and** plain objects containing refs.

## Convert Existing Refs to Reactive Variables with `$()` {#convert-existing-refs-to-reactive-variables-with}

In some cases we may have wrapped functions that also return refs. However, the Vue compiler won't be able to know ahead of time that a function is going to return a ref. In such cases, the `$()` macro can also be used to convert any existing refs into reactive variables:

```js twoslash
import { ref } from 'vue'

function myCreateRef() {
  return ref(0)
}

const count = $(myCreateRef())
```

## Reactive Props Destructure {#reactive-props-destructure}

There are two pain points with the current `defineProps()` usage in `<script setup>`:

1. Similar to `.value`, you need to always access props as `props.x` in order to retain reactivity. This means you cannot destructure `defineProps` because the resulting destructured variables are not reactive and will not update.

2. When using the [type-only props declaration](https://vuejs.org/api/sfc-script-setup.html#typescript-only-features), there is no easy way to declare default values for the props. We introduced the `withDefaults()` API for this exact purpose, but it's still clunky to use.

We can address these issues by applying a compile-time transform when `defineProps` is used with destructuring, similar to what we saw earlier with `$()`:

```vue twoslash
<script setup lang="ts">
import { watchEffect } from 'vue'

interface Props {
  msg: string
  count?: number
  foo?: string
}

const {
  msg,
  // default value just works
  count = 1,
  // local aliasing also just works
  // here we are aliasing `props.foo` to `bar`
  foo: bar,
} = defineProps<Props>()

watchEffect(() => {
  // will log whenever the props change
  console.log(msg, count, bar)
})
</script>
```

The above will be compiled into the following runtime declaration equivalent:

```ts twoslash
import { defineComponent, watchEffect } from 'vue'

export default defineComponent({
  props: {
    msg: { type: String, required: true },
    count: { type: Number, default: 1 },
    foo: String,
  },
  setup(props) {
    watchEffect(() => {
      console.log(props.msg, props.count, props.foo)
    })
  },
})
```

## Retaining Reactivity Across Function Boundaries {#retaining-reactivity-across-function-boundaries}

While reactive variables relieve us from having to use `.value` everywhere, it creates an issue of "reactivity loss" when we pass reactive variables across function boundaries. This can happen in two cases:

### Passing into function as argument {#passing-into-function-as-argument}

Given a function that expects a ref as an argument, e.g.:

```ts twoslash
import { watch, type Ref } from 'vue'

function trackChange(x: Ref<number>) {
  watch(x, (x) => {
    console.log('x changed!')
  })
}

const count = $ref(0)
// @errors: 2345
trackChange(count) // doesn't work!
```

The above case will not work as expected because it compiles to:

```ts
const count = ref(0)
trackChange(count.value)
```

Here `count.value` is passed as a number, whereas `trackChange` expects an actual ref. This can be fixed by wrapping `count` with `$()` before passing it:

```diff
let count = $ref(0)
- trackChange(count)
+ trackChange($(count))
```

The above compiles to:

```js
import { ref } from 'vue'

const count = ref(0)
trackChange(count)
```

As we can see, `$()` is a macro that serves as an **escape hint**: reactive variables inside `$()` will not get `.value` appended.

### Returning inside function scope {#returning-inside-function-scope}

Reactivity can also be lost if reactive variables are used directly in a returned expression:

```ts twoslash
function useMouse() {
  const x = $ref(0)
  const y = $ref(0)

  // listen to mousemove...

  // doesn't work!
  return {
    x,
    y,
  }
}
```

The above return statement compiles to:

```ts
return {
  x: x.value,
  y: y.value,
}
```

In order to retain reactivity, we should be returning the actual refs, not the current value at return time.

Again, we can use `$()` to fix this. In this case, `$()` can be used directly on the returned object - any reference to reactive variables inside the `$()` call will retain the reference to their underlying refs:

```ts twoslash
function useMouse() {
  const x = $ref(0)
  const y = $ref(0)

  // listen to mousemove...

  // fixed
  return $({
    x,
    y,
  })
}
```

### Using `$()` on destructured props {#using-on-destructured-props}

`$()` works on destructured props since they are reactive variables as well. The compiler will convert it with `toRef` for efficiency:

```vue twoslash
<script setup lang="ts">
import type { Ref } from 'vue'
function passAsRef(count: Ref<number>) {
  return count
}
// ---cut---
const { count } = defineProps<{ count: number }>()

passAsRef($(count))
</script>
```

compiles to:

```ts twoslash
import { defineComponent, toRef, type Ref } from 'vue'
function passAsRef(count: Ref<number>) {
  return count
}
// ---cut---
export default defineComponent({
  props: {
    count: { type: Number, required: true },
  },
  setup(props) {
    const __props_count = toRef(props, 'count')
    passAsRef(__props_count)
  },
})
```

## TypeScript Integration  {#typescript-integration}

Vue provides typings for these macros (available globally) and all types will work as expected. There are no incompatibilities with standard TypeScript semantics, so the syntax will work with all existing tooling.

This also means the macros can work in any files where valid JS / TS are allowed - not just inside Vue SFCs.

Since the macros are available globally, their types need to be explicitly referenced (e.g. in a `env.d.ts` file):

```ts [env.d.ts]
/// <reference types="vue-macros/macros-global" />

// or for standalone version:
/// <reference types="@vue-macros/reactivity-transform/macros-global" />
```

When explicitly importing the macros from `vue-macros/macros` or `@vue-macros/reactivity-transform/macros-global`, the type will work without declaring the globals.

---

---
url: /features/script-lang.md
---
# scriptLang&#x20;

Set the default language for `<script>` block.

::: tip
Convert `<script setup>` to `<script setup lang="ts">`.
:::

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

## Options

```ts
interface Options {
  /**
   * @default 'ts'
   */
  defaultLang?: 'ts' | 'tsx' | 'jsx' | string
}
```

## Usage

```vue twoslash
<script setup>
defineProps<{
  foo: string
}>()
</script>
```

## Volar Configuration

```jsonc {3,5-7} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "scriptLang": {
        "defaultLang": "ts",
      },
    },
  },
}
```

---

---
url: /volar/script-sfc.md
---
# scriptSFC&#x20;

Enabled Volar support for `.ts` | `.tsx` files.

|   Features   |     Supported      |
| :----------: | :----------------: |
| Volar Plugin | :white\_check\_mark: |

## Basic Usage

### With `jsxDirective`

::: code-group

```tsx [App.tsx]
export default ({ foo }: { foo: number }) => (
  <div v-if={foo === 1}>{foo}</div>
  //                     ^ will be inferred as 1
)
```

:::

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["@vue-macros/volar"],
    "vueMacros": {
      "scriptSFC": true,
    },
  },
}
```

---

---
url: /macros/setup-component.md
---
# setupComponent&#x20;

::: tip

`defineRender` cannot be disabled when using `setupComponent`.

Files in `node_modules` will be ignored by default.

:::

With `defineSetupComponent`, `<script setup>` code can be put in **pure JS/TS(X)** without [Vue Language Tools (Volar)](https://github.com/johnsoncodehk/volar) extension.

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Nuxt 3   |        :x:         |
|   Vue 2    |        :x:         |
| TypeScript |        :x:         |

See also [Vue Vine](https://vue-vine.dev/) - another style for Vue functional component.

## Basic Usage

```tsx twoslash
export const App = defineSetupComponent(() => {
  defineProps<{
    foo: string
  }>()

  defineEmits<{
    (evt: 'change'): void
  }>()

  defineOptions({
    name: 'App',
  })

  // ...
  return <div />
})
```

## Type Annotation

```ts twoslash
export const App: SetupFC = () => {
  defineProps<{
    foo: string
  }>()

  defineEmits<{
    (evt: 'change'): void
  }>()

  defineOptions({
    name: 'App',
  })
}
```

## Known Issues

* TypeScript support is not yet completed.
* The source map does not correspond properly.

---

---
url: /volar/setup-jsdoc.md
---
# setupJsdoc&#x20;

Define the component's JSDoc in the script setup block.

|   Features   |     Supported      |
| :----------: | :----------------: |
| Volar Plugin | :white\_check\_mark: |

## Basic Usage

````vue twoslash
<script setup lang="tsx">
/**
 * @example
 * ```vue
 * <Comp :foo="1" />
 * ```
 */
const Comp = () => <div />
// ---cut---
// @noErrors
import Comp from './Comp.vue'
//     ^?
</script>

<template>
  <Comp />
</template>
````

### There are two places to define

1. The first line of the script setup block.

````vue
<script setup lang="ts">
/**
 * @example
 * ```vue
 * <Comp :foo="1" />
 * ```
 */

defineProps<{
  foo: number
}>()
</script>
````

2. Above the `export default` expression.

::: tip

This feature depends on `exportRender`, and make sure `exportRender` is not disabled.

:::

````vue
<script setup lang="tsx">
defineProps<{
  foo: number
}>()

/**
 * @example
 * ```vue
 * <Comp :foo="1" />
 * ```
 */
export default <div />
</script>
````

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/setup-sfc.md
---
# setupSFC&#x20;

::: tip

If you're using `setupSFC`, then `defineRender` cannot be disabled.

:::

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|       Nuxt 3       | :white\_check\_mark: |
|       Vue 2        | :white\_check\_mark: |
| TypeScript / Volar | :white\_check\_mark: |

## Setup

::: code-group

```ts {7-14} [Vite]
// vite.config.ts
import Vue from '@vitejs/plugin-vue'
import VueMacros from 'vue-macros/vite'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue({
          include: [/\.vue$/, /\.setup\.[cm]?[jt]sx?$/],
          //                   ⬆️ setupSFC pattern need to be added
        }),
      },
    }),
  ],
})
```

```ts {6-13} [Rollup]
import Vue from 'unplugin-vue/rollup'
import VueMacros from 'vue-macros/rollup'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue({
          include: [/\.vue$/, /\.setup\.[cm]?[jt]sx?$/],
          //                   ⬆️ setupSFC pattern need to be added
        }),
      },
    }),
  ],
})
```

```[🚧 esbuild]
🚧
```

```[🚧 Webpack]
🚧
```

:::

## Basic Usage

```tsx twoslash
// Foo.setup.tsx
defineProps<{
  foo: string
}>()

defineEmits<{
  (evt: 'change'): void
}>()

export default () => (
  <div>
    <h1>Hello World</h1>
  </div>
)
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "setupSFC": true,
    },
  },
}
```

---

---
url: /features/short-bind.md
---
# shortBind&#x20;

`:value` -> `:value="value"`

Same-name shorthand for binding prop. If the attribute has the same name with the JavaScript value being bound, the syntax can be further shortened to omit the attribute value.

For Vue >= 3.4, this feature will be turned off by default.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     |        :x:         |
| Volar Plugin | :white\_check\_mark: |

## Usage

### Basic Usage

```vue twoslash
<script setup>
const value = 'foo'
</script>

<template>
  <input :value />
  <!-- => <input :foo="value" /> -->
</template>
```

### With `shortVmodel`

```vue
<template>
  <Comp ::value />
  <!-- => <Comp ::foo="foo" /> => <Comp v-model:foo="foo" /> -->
  <Comp $foo />
  <!-- => <Comp $foo="foo" /> => <Comp v-model:foo="foo" /> -->
  <Comp *foo />
  <!-- => <Comp *foo="foo" /> => <Comp v-model:foo="foo" /> -->
</template>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/short-emits.md
---
# shortEmits&#x20;

Simplify the definition of emits.

For Vue >= 3.3, this feature will be turned off by default.

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Vue 2    | :white\_check\_mark: |
| TypeScript | :white\_check\_mark: |

## Basic Usage

```vue twoslash
<script setup lang="ts">
import { defineEmits } from 'vue-macros/macros'

const emits = defineEmits<{
  // tuple
  'update:modelValue': [val: string]
  // function
  update: (val: string) => void
}>()
</script>
```

Using type `ShortEmits` or for short `SE`.

```vue twoslash
<script setup lang="ts">
const emits = defineEmits<
  SE<{
    // tuple
    'update:modelValue': [val: string]
    // function
    update: (val: string) => void
  }>
>()
</script>
```

## Difference with Official Version

* function style of declaration is not supported by official version.

---

---
url: /macros/short-vmodel.md
---
# shortVmodel&#x20;

A shorthand for `v-model`.

`v-model` -> `::` / `


  
  
  
  
  vue-macros.dev | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


   / `*`

If you have any questions about this feature, you can comment on [RFC Discussion](https://github.com/vuejs/rfcs/discussions/395).

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     |        :x:         |
| Volar Plugin | :white\_check\_mark: |

## Options

```ts
interface Options {
  /**
   * @default '
#x27; */ prefix?: '::' | '
#x27; | '*' } ``` ## Usage ### ` vue-macros.dev | Top Sites | DialtoneApp Dollar Sign (Default) ```vue <template> <input $="msg" /> <!-- => <input v-model="msg" /> --> <demo $msg="msg" /> <!-- => <input v-model:msg="msg" /> --> </template> ``` ### `::` Double Binding ```vue <template> <!-- prettier-ignore --> <input ::="msg" /> <!-- => <input v-model="msg" /> --> <demo ::msg="msg" /> <!-- => <input v-model:msg="msg" /> --> </template> ``` ### `*` Asterisk Sign ```vue <template> <input *="msg" /> <!-- => <input v-model="msg" /> --> <demo *msg="msg" /> <!-- => <input v-model:msg="msg" /> --> </template> ``` ## Volar Configuration ```jsonc {3,5-7} [tsconfig.json] { "vueCompilerOptions": { "plugins": ["vue-macros/volar"], "vueMacros": { "shortVmodel": { "prefix": "
quot;, }, }, }, } ``` ## Known Issues * Prettier will format `::=` to `:=` (e.g. `<div ::="msg" />` -> `<div :="msg" />`). The comment `<!-- prettier-ignore -->` is required if prefix is `::`. --- --- url: /volar/template-ref.md --- # templateRef&#x20; Automatically infer type for `templateRef` (from [VueUse](https://vueuse.org/core/templateRef/)) and `useTemplateRef` (Vue 3.5+). ::: warning This feature is officially supported since Volar (`vue-tsc`) v2.1.0. Vue Macros is no longer offering this feature as a plugin. ::: | Features | Supported | | :------: | :----------------: | | Volar | :white\_check\_mark: | ## Basic Usage ::: code-group ```vue [App.vue] twoslash <script setup lang="ts"> // #region comp import { defineComponent } from 'vue' export const Comp = defineComponent({ setup() { return { foo: 1 } }, }) // #endregion comp // ---cut--- import { templateRef } from '@vueuse/core' // @noErrors import { Comp } from './Comp.ts' const comp = templateRef('comp') comp.value?.foo // ^? </script> <template> <Comp ref="comp" /> </template> ``` <<< ./template-ref.md#comp{ts} \[Comp.ts] ::: ## Volar Configuration No configuration required. --- --- url: /macros.md --- # Usage List of all available macros. Please make sure `vue-macros` is set up correctly. If you haven't yet, read [Getting Started](../guide/getting-started.md) first. ## Implemented by Vue 3.3 * [defineOptions](./define-options.md) * [defineSlots](./define-slots.md) * [shortEmits](./short-emits.md) ## Stable Features * [defineModels](./define-models.md) * [defineProps](./define-props.md) * [definePropsRefs](./define-props-refs.md) * [defineRender](./define-render.md) * [shortVmodel](./short-vmodel.md) ## Experimental Features * [defineProp](./define-prop.md) * [defineEmit](./define-emit.md) * [setupComponent](./setup-component.md) * [setupSFC](./setup-sfc.md) * [chainCall](./chain-call.md) * [defineStyleX](./define-stylex.md)
:\n\n`v-model`\n\n::: code-group\n\n```vue [App.vue] twoslash\n\u003cscript setup lang=\"tsx\"\u003e\n// ---cut-start---\n// #region v-model\nimport { ref, type FunctionalComponent } from 'vue'\n\nexport const Comp: FunctionalComponent\u003c\n {\n model: string\n models: string[]\n },\n {\n 'update:model': [value: string]\n 'update:models': [value: string[]]\n }\n\u003e = () =\u003e \u003cdiv /\u003e\n// #endregion v-model\n// ---cut-end---\n// @noErrors\nimport { Comp } from './Comp.tsx'\n\nconst name = ref('model')\nconst model = defineModel\u003cstring\u003e()\n\nexport default () =\u003e (\n \u003cComp\n v-model:$name$={model.value}\n v-model:model={model.value}\n // ^|\n /\u003e\n)\n\u003c/script\u003e\n```\n\n\u003c\u003c\u003c ./jsx-directive.md#v-model{tsx} \\[Comp.tsx]\n\n:::\n\n`v-slot`\n\n::: code-group\n\n```vue [App.vue] twoslash\n\u003cscript setup lang=\"tsx\"\u003e\n// ---cut-start---\n// #region v-slot-dynamic\nimport type { FunctionalComponent } from 'vue'\n\nexport const Comp: FunctionalComponent\u003c\n {},\n {},\n {\n default: (scope: { foo: string }) =\u003e any\n title: (scope: { bar: number }) =\u003e any\n }\n\u003e = () =\u003e \u003cdiv /\u003e\n// #endregion v-slot-dynamic\n// ---cut-end---\n// @noErrors\nimport { Comp } from './Comp.tsx'\n\nconst slots = defineSlots\u003c{\n default: (scope: { foo: string }) =\u003e any\n title: (scope: { bar: number }) =\u003e any\n}\u003e()\n\n// ---cut-start---\n// prettier-ignore\n// ---cut-end---\nexport default () =\u003e (\n \u003cComp\u003e\n \u003ctemplate v-for={(Slot, name) in slots} v-slot:$name$={scope}\u003e\n // ^?\n \u003cSlot {...scope} /\u003e\n \u003c/template\u003e\n \u003c/Comp\u003e\n)\n\u003c/script\u003e\n```\n\n\u003c\u003c\u003c ./jsx-directive.md#v-slot-dynamic{tsx} \\[Comp.tsx]\n\n:::\n\n## Modifiers\n\nModifiers are special postfixes denoted by a `_`, which indicate that a directive should be bound in some special way.\n\n```tsx\n\u003cform onSubmit_prevent\u003e\n \u003cinput v-model_number={value} /\u003e\n\u003c/form\u003e\n```\n\n## Volar Configuration\n\n```jsonc {3} [tsconfig.json]\n{\n \"vueCompilerOptions\": {\n \"plugins\": [\"vue-macros/volar\"],\n },\n}\n```\n\n---\n\n---\nurl: /volar/jsx-ref.md\n---\n# jsxRef\u0026#x20;\n\nAutomatically infer type for `useRef`.\n\n| Features | Supported |\n| :------: | :----------------: |\n| Volar | :white\\_check\\_mark: |\n\n## Setup Auto Import\n\n::: code-group\n\n```ts [vite.config.ts]\nimport AutoImport from 'unplugin-auto-import/vite'\n\nexport default defineConfig({\n plugins: [\n AutoImport({\n imports: [\n {\n from: 'vue',\n imports: [['shallowRef', 'useRef']],\n },\n ],\n }),\n ],\n})\n```\n\n```ts [nuxt.config.ts]\nexport default defineNuxtConfig({\n imports: {\n presets: [\n {\n from: 'vue',\n imports: [['shallowRef', 'useRef']],\n },\n ],\n },\n})\n```\n\n:::\n\n## Basic Usage\n\n::: code-group\n\n```vue [App.vue] twoslash\n\u003cscript lang=\"tsx\"\u003e\n// #region comp\nimport { defineComponent } from 'vue'\n\nexport const Comp = defineComponent({\n setup() {\n return { foo: 1 }\n },\n})\n// #endregion comp\n// ---cut---\nimport { useRef } from 'vue-macros/runtime'\n// Or import { shallowRef as useRef } from 'vue'\n// @noErrors\nimport { Comp } from './Comp.ts'\n\nexport default defineComponent(() =\u003e {\n const comp = useRef()\n comp.value?.foo\n // ^?\n\n return () =\u003e (\n \u003c\u003e\n \u003cComp ref={comp} /\u003e\n \u003c/\u003e\n )\n})\n\u003c/script\u003e\n```\n\n\u003c\u003c\u003c ./jsx-ref.md#comp{ts} \\[Comp.ts]\n\n:::\n\n## Volar Configuration\n\n```jsonc [tsconfig.json] {3,6}\n{\n \"vueCompilerOptions\": {\n \"plugins\": [\"vue-macros/volar\"],\n \"vueMacros\": {\n \"jsxRef\": {\n \"alias\": [\"useRef\"],\n },\n },\n },\n}\n```\n\n---\n\n---\nurl: /guide/migration-v3.md\n---\n# Migration from v2 to v3\n\n## Unified Version Management\n\nInitially, we used [`changesets`](https://github.com/changesets/changesets) to\nmanage the versions of all packages in the monorepo. However, after two years of experimentation,\nwe decided to adopt a single-version strategy in v3,\nwhere all sub-packages share the same version number, similar to Vue and Babel.\nThis decision stemmed from our observation that when a sub-package underwent a major change or minor update,\nthe version number of the main package did not adequately reflect these changes.\n\nFor example, when `@vue-macros/define-prop` introduced a breaking change,\nhow should `unplugin-vue-macros` release a new version?\nShould it be a minor or a patch release? When users updated `unplugin-vue-macros`,\nthey couldn’t easily determine whether the update was due to changes in `@vue-macros/define-prop`.\n\nTherefore, after Anthony proposed [Epoch Semantic Versioning](https://antfu.me/posts/epoch-semver),\nwe decided to adopt a more frequent major version update strategy,\nwith all packages sharing the same version number and maintaining a single unified changelog.\n\n## Main Package Rename\n\nWe have renamed the main package from `unplugin-vue-macros` to **`vue-macros`**.\nAfter the official release of v3, `unplugin-vue-macros` will be marked as deprecated.\n\nAs a result, you will need to update your `package.json` and the import statements for Vue Macros:\n\n```diff\n // package.json\n {\n \"devDependencies\": {\n- \"unplugin-vue-macros\": \"^2.14.5\"\n+ \"vue-macros\": \"^3.0.0\"\n }\n }\n```\n\n```diff\n- import { $ref } from 'unplugin-vue-macros/macros'\n+ import { $ref } from 'vue-macros/macros'\n\n- import VueMacros from 'unplugin-vue-macros/vite'\n+ import VueMacros from 'vue-macros/vite'\n```\n\n## Dropping Vue 2 Support\n\nVue 2 reached its end of life (EOL) at the end of 2023, so we have decided to drop support for Vue 2 in v3.\nIf you are still using Vue 2, we recommend continuing with v2 or\nconsidering our [paid support plan](https://github.com/vue-macros/vue-macros/issues/373).\n\n## Node.js Compatibility Changes\n\nIn v3, we have dropped support for Node.js versions below 20.19.\nThis means the minimum Node.js version requirement for v3 is `20.19.0`.\nAdditionally, we have removed CommonJS (CJS) outputs and now only provide ECMAScript modules (ESM).\n\n## Dropping Webpack 4 Support\n\nSince Webpack 4 cannot run in Node.js 18 or later environments,\nwe have also dropped support for Webpack 4 and Vue CLI 4.\nWe recommend upgrading to modern build tools like Vite or Rspack.\n\n---\n\n---\nurl: /features/named-template.md\n---\n# namedTemplate\u0026#x20;\n\n::: warning\n\nNot actively maintained now. Try [createReusableTemplate](https://vueuse.org/core/createReusableTemplate/) instead.\n\n:::\n\nWith enabling `namedTemplate`, `\u003ctemplate\u003e` can be referenced like a variable.\n\nSometimes we need to reverse the order of the very simple components, and don't want to give the features of Vue template up and use JSX/TSX. Then this feature is much helpful.\n\nIf you support this feature, you can go to [the discussion](https://github.com/vuejs/core/discussions/6898) and hit like :+1: or comment.\n\n| Features | Supported |\n| :----------------: | :----------------: |\n| Vue 3 | :white\\_check\\_mark: |\n| Vue 3.3 | :x: |\n| Nuxt 3 | :x: |\n| Vue 2 | :x: |\n| TypeScript / Volar | :x: |\n\n## Basic Usage\n\n```vue {5-7,10-12,16-18}\n\u003cscript setup\u003e\nconst pager = 'top'\n\u003c/script\u003e\n\n\u003ctemplate name=\"pager\"\u003e\n \u003cspan\u003eThis is pager\u003c/span\u003e\n\u003c/template\u003e\n\n\u003ctemplate\u003e\n \u003ctemplate v-if=\"pager === 'top'\"\u003e\n \u003ctemplate is=\"pager\" /\u003e\n \u003c/template\u003e\n\n \u003cspan\u003eHere is data table\u003c/span\u003e\n\n \u003ctemplate v-if=\"pager === 'bottom'\"\u003e\n \u003ctemplate is=\"pager\" /\u003e\n \u003c/template\u003e\n\u003c/template\u003e\n```\n\n## Known Usage\n\n* TypeScript / Volar support is not yet completed.\n\n---\n\n---\nurl: /features/reactivity-transform.md\n---\n# Reactivity Transform\u0026#x20;\n\n| Features | Supported |\n| :----------------: | :----------------: |\n| Vue 3 | :white\\_check\\_mark: |\n| Nuxt 3 | :white\\_check\\_mark: |\n| Vue 2 | :white\\_check\\_mark: |\n| TypeScript / Volar | :white\\_check\\_mark: |\n\n## Installation Standalone Version\n\nif you need Reactivity Transform feature only, the standalone version is more appropriate for you.\n\n### Installation\n\n::: code-group\n\n```bash [npm]\nnpm i -D @vue-macros/reactivity-transform\n```\n\n```bash [yarn]\nyarn add -D @vue-macros/reactivity-transform\n```\n\n```bash [pnpm]\npnpm add -D @vue-macros/reactivity-transform\n```\n\n:::\n\n::: code-group\n\n```ts [Vite]\n// vite.config.ts\nimport ReactivityTransform from '@vue-macros/reactivity-transform/vite'\n\nexport default defineConfig({\n plugins: [ReactivityTransform()],\n})\n```\n\n```ts [Rollup]\n// rollup.config.js\nimport ReactivityTransform from '@vue-macros/reactivity-transform/rollup'\n\nexport default {\n plugins: [ReactivityTransform()],\n}\n```\n\n```js [esbuild]\n// esbuild.config.js\nimport { build } from 'esbuild'\n\nbuild({\n plugins: [require('@vue-macros/reactivity-transform/esbuild')()],\n})\n```\n\n```js [Webpack]\n// webpack.config.js\nmodule.exports = {\n /* ... */\n plugins: [require('@vue-macros/reactivity-transform/webpack')()],\n}\n```\n\n:::\n\n### TypeScript Support\n\n```json [tsconfig.json]\n{\n \"compilerOptions\": {\n // ...\n \"types\": [\"@vue-macros/reactivity-transform/macros-global\" /* ... */]\n }\n}\n```\n\n## Refs vs. Reactive Variables {#refs-vs-reactive-variables}\n\nEver since the introduction of the Composition API, one of the primary unresolved questions is the use of refs vs. reactive objects. It's easy to lose reactivity when destructuring reactive objects, while it can be cumbersome to use `.value` everywhere when using refs. Also, `.value` is easy to miss if not using a type system.\n\nReactivity Transform is a compile-time transform that allows us to write code like this:\n\n```vue twoslash\n\u003cscript setup\u003e\nlet count = $ref(0)\n\nconsole.log(count)\n\nfunction increment() {\n count++\n}\n\u003c/script\u003e\n\n\u003ctemplate\u003e\n \u003cbutton @click=\"increment\"\u003e{{ count }}\u003c/button\u003e\n\u003c/template\u003e\n```\n\nThe `$ref()` method here is a **compile-time macro**: it is not an actual method that will be called at runtime. Instead, the Vue compiler uses it as a hint to treat the resulting `count` variable as a **reactive variable.**\n\nReactive variables can be accessed and re-assigned just like normal variables, but these operations are compiled into refs with `.value`. For example, the `\u003cscript\u003e` part of the above component is compiled into:\n\n```js{5,8} twoslash\nimport { ref } from 'vue'\n\nlet count = ref(0)\n\nconsole.log(count.value)\n\nfunction increment() {\n count.value++\n}\n```\n\nEvery reactivity API that returns refs will have a ` vue-macros.dev | Top Sites | DialtoneApp

Top SitesVue Macros

Machine Readiness

Stored receipt and evidence

Overall

27

Readable

90

Callable

0

Commerce

0

Payment

0

Machine Access

Inspect the site's MCP endpoint

Open MCP explorer

DialtoneApp can scan the stored discovery files for this domain, try the MCP initialize handshake, and show the raw protocol transcript.

Purchase boundary

read only

Control boundary

unknown

Payment rails

None

Payment providers

None

Payment methods

None

Payment protocols

None

Payment assets

None

Payment networks

None

Capabilities

None

Verified payment surface

No

Crypto only

No

Readable docs

llms, llms-full

Products

0

Variants

0

Priced variants

0

Currencies

0

Offers

0

Priced offers

0

Priced actions

0

Samples

Offer samples

No stored offer samples.

Samples

Action samples

No stored action samples.

Samples

Product samples

No stored product samples.

Document

robots.txt

Not stored for this site.

Document

llms.txt

Open llms.txt
# Vue Macros

> Modern Way to Writing Vue App

Explore more macros and syntax sugar to Vue.

## Table of Contents

- [&#x20;ESLint Integration&#x20;](/guide/eslint-integration.md)
- [&#x20;Nuxt Integration&#x20;](/guide/nuxt-integration.md)
- [Astro Integration&#x20;](/guide/astro-integration.md)
- [betterDefine&#x20;](/features/better-define.md)
- [booleanProp&#x20;](/features/boolean-prop.md)
- [Bundler Integration&#x20;](/guide/bundler-integration.md)
- [chainCall&#x20;](/macros/chain-call.md)
- [Configurations](/guide/configurations.md)
- [defineEmit&#x20;](/macros/define-emit.md)
- [defineGeneric&#x20;](/volar/define-generic.md)
- [defineModels&#x20;](/macros/define-models.md)
- [defineOptions&#x20;](/macros/define-options.md)
- [defineProp&#x20;](/macros/define-prop.md)
- [defineProps&#x20;](/macros/define-props.md)
- [definePropsRefs&#x20;](/macros/define-props-refs.md)
- [defineRender&#x20;](/macros/define-render.md)
- [defineSlots&#x20;](/macros/define-slots.md)
- [defineStyleX&#x20;](/macros/define-stylex.md)
- [exportExpose&#x20;](/features/export-expose.md)
- [exportProps&#x20;](/features/export-props.md)
- [exportRender&#x20;](/features/export-render.md)
- [Getting Started](/guide/getting-started.md)
- [hoistStatic&#x20;](/features/hoist-static.md)
- [jsxDirective&#x20;](/features/jsx-directive.md)
- [jsxRef&#x20;](/volar/jsx-ref.md)
- [Migration from v2 to v3](/guide/migration-v3.md)
- [namedTemplate&#x20;](/features/named-template.md)
- [Reactivity Transform&#x20;](/features/reactivity-transform.md)
- [scriptLang&#x20;](/features/script-lang.md)
- [scriptSFC&#x20;](/volar/script-sfc.md)
- [setupComponent&#x20;](/macros/setup-component.md)
- [setupJsdoc&#x20;](/volar/setup-jsdoc.md)
- [setupSFC&#x20;](/macros/setup-sfc.md)
- [shortBind&#x20;](/features/short-bind.md)
- [shortEmits&#x20;](/macros/short-emits.md)
- [shortVmodel&#x20;](/macros/short-vmodel.md)
- [templateRef&#x20;](/volar/template-ref.md)
- [Usage](/macros.md)

Document

llms-full.txt

Open llms-full.txt
---
url: /guide/eslint-integration.md
---
# &#x20;ESLint Integration&#x20;

## Installation

::: code-group

```bash [pnpm]
pnpm add -D @vue-macros/eslint-config
```

```bash [yarn]
yarn add -D @vue-macros/eslint-config
```

```bash [npm]
npm i -D @vue-macros/eslint-config
```

:::

## Configuration

### Flat Configuration

```js [eslint.config.js]
import vueMacros from '@vue-macros/eslint-config/flat'
export default [
  vueMacros,
  // ...your other configurations
]
```

### Legacy Configuration

```jsonc [.eslintrc]
{
  "extends": [
    "@vue-macros/eslint-config",
    // ...your other configurations
  ],
}
```

---

---
url: /guide/nuxt-integration.md
---
# &#x20;Nuxt Integration&#x20;

### Installation

::: code-group

```bash [npm]
npm i -D @vue-macros/nuxt
```

```bash [yarn]
yarn add -D @vue-macros/nuxt
```

```bash [pnpm]
pnpm add -D @vue-macros/nuxt
```

:::

## Configuration

```ts [nuxt.config.ts]
export default {
  modules: [
    '@vue-macros/nuxt',
    // ...
  ],
  macros: {
    // overrides config options
  },
}
```

***

:tada: Congratulations! That's all.

To learn more about the macros, please visit [All Macros](/macros/) :laughing:.

---

---
url: /guide/astro-integration.md
---
# Astro Integration&#x20;

### Installation

::: code-group

```bash [npm]
npm i -D @vue-macros/astro
```

```bash [yarn]
yarn add -D @vue-macros/astro
```

```bash [pnpm]
pnpm add -D @vue-macros/astro
```

:::

## Configuration

```ts [astro.config.mjs]
import Vue from '@astrojs/vue'
import Macros from '@vue-macros/astro'
import { defineConfig } from 'astro/config'

export default defineConfig({
  integrations: [
    Vue(),
    Macros({
      // overrides config options
    }),
  ],
})
```

## TypeScript Support & Volar Support

See the corresponding chapter on [Bundler Integration](./bundler-integration.md#typescript-support)

***

:tada: Congratulations! That's all.

To learn more about the macros, please visit [All Macros](/macros/) :laughing:.

---

---
url: /features/better-define.md
---
# betterDefine&#x20;

With enabling `betterDefine`, imported types are supported in `<script setup>` type-based-macros.

[Related issue](https://github.com/vuejs/core/issues/4294)

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Nuxt 3   | :white\_check\_mark: |
|   Vue 2    | :white\_check\_mark: |
| TypeScript | :white\_check\_mark: |

## Basic Usage

::: code-group

```vue twoslash [App.vue]
<script setup lang="ts">
// #region basic
type BaseProps = {
  title: string
}

export type { BaseProps }
// #endregion basic
// ---cut---
// @noErrors
import type { BaseProps } from './types'

interface Props extends BaseProps {
  foo: string
}
const props = defineProps<Props>()
</script>
```

<<< ./better-define.md#basic{ts} \[types.ts]

:::

## ⚠️ Limitations

### Complex types

Complex types are not supported in some key places. For example:

#### What are Complex Types?

* All utility types
  * [Built-in types](https://www.typescriptlang.org/docs/handbook/utility-types.html)
  * All types from `type-fest` package.
  * `typeof` keyword.
  * ...
* Index Signature
  ```ts
  interface Type {
    [key: string]: string
  }
  ```
* Generics will be ignored directly

#### What are Key Places?

* The names of props.

```ts
// ✅
defineProps<{
  foo: ComplexType
}>()

// ❌
defineProps<{
  [ComplexType]: string
}>()
```

* The names of emits.

```ts
interface Emits {
  (event: 'something', value: ComplexType): void // ✅
  (event: ComplexType): void // ❌
}
```

---

---
url: /features/boolean-prop.md
---
# booleanProp&#x20;

Convert `<Comp checked />` to `<Comp :checked="true" />`.

Convert `<Comp !checked />` to `<Comp :checked="false" />`.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     |        :x:         |
| Volar Plugin | :white\_check\_mark: |

## Options

```ts
interface Options {
  /**
   * @default '!'
   */
  negativePrefix?: string
}
```

## Usage

```vue twoslash
<script setup>
import type { FunctionalComponent } from 'vue'

export const Comp: FunctionalComponent<
  {
    checked: true,
    enabled: false,
  },
> = () => null
// ---cut---
// @noErrors
import Comp from './Comp.vue'
</script>

<template>
  <Comp checked !enabled />
  //             ^?
</template>
```

```vue twoslash
<script setup lang="ts">
// Comp.vue
defineProps<{
  checked: true
  enabled: false
}>()
</script>
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "booleanProp": true,
    },
  },
}
```

---

---
url: /guide/bundler-integration.md
---
# Bundler Integration&#x20;

## Installation

::: tip

Vite and Rollup are fully supported, while other bundlers have limited support.

:::

::: code-group

```bash [npm]
npm i -D vue-macros
```

```bash [yarn]
yarn add -D vue-macros
```

```bash [pnpm]
pnpm add -D vue-macros
```

:::

::: code-group

```ts [Vite]
// vite.config.ts
import Vue from '@vitejs/plugin-vue'
import VueMacros from 'vue-macros/vite'
// import VueJsx from '@vitejs/plugin-vue-jsx'
// import VueRouter from 'unplugin-vue-router/vite'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue(),
        // vueJsx: VueJsx(), // if needed
        // vueRouter: VueRouter({ // if needed
        //   extensions: ['.vue', '.setup.tsx']
        // })
      },
      // overrides plugin options
    }),
  ],
})
```

```ts [Rollup]
// rollup.config.js (Requires Rollup 3+)
import Vue from 'unplugin-vue/rollup'
import VueMacros from 'vue-macros/rollup'
// import VueRouter from 'unplugin-vue-router/rollup'

export default {
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue(),
        // vueJsx: VueJsx(), // if needed
        // vueRouter: VueRouter({ // if needed
        //   extensions: ['.vue', '.setup.tsx']
        // })
      },
      // overrides plugin options
    }),
  ],
}
```

```js [esbuild]
// esbuild.config.js
import { build } from 'esbuild'
// import VueRouter from 'unplugin-vue-router/esbuild'

build({
  plugins: [
    require('vue-macros/esbuild')({
      plugins: {
        vue: require('unplugin-vue/esbuild')(),
        // vueJsx: VueJsx(), // if needed
        // vueRouter: VueRouter({ // if needed
        //   extensions: ['.vue', '.setup.tsx']
        // })
      },
      // overrides plugin options
    }),
  ],
})
```

```js [Webpack]
// webpack.config.js (Requires Webpack 5+)
module.exports = {
  /* ... */
  plugins: [
    require('vue-macros/webpack')({
      // overrides plugin options
    }),
  ],
}
```

```js [Rspack]
// rspack.config.js
module.exports = {
  /* ... */
  plugins: [
    require('vue-macros/rspack')({
      // overrides plugin options
    }),
  ],
}
```

```js [Rsbuild]
// rsbuild.config.js
module.exports = {
  // ...
  tools: {
    rspack: {
      plugins: [
        require('vue-macros/rspack')({
          // overrides plugin options
        }),
      ],
    },
  },
}
```

```js [Vue CLI]
// vue.config.js (Requires Vue CLI 5+)
const { defineConfig } = require('@vue/cli-service')
const VueMacros = require('vue-macros/webpack')

module.exports = defineConfig({
  // ...
  // ⚠️ IMPORTANT
  parallel: false,
  configureWebpack: {
    plugins: [
      VueMacros({
        // overrides plugin options
      }),
    ],
  },
})
```

:::

## Configuration

See the [Configurations](./configurations.md) for more details.

```ts twoslash [vue-macros.config.ts]
import { defineConfig } from 'vue-macros'
export default defineConfig({
  // options
})
```

## TypeScript Support

```json {0}
// tsconfig.json
{
  "compilerOptions": {
    // ...
    "types": ["vue-macros/macros-global" /* ... */]
  }
}
```

## Volar Support

For detailed configuration, please refer to the description of the specific macro.

```jsonc [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

### Scoped Plugins

`exportExpose`, `exportProps`, and `exportRender` plugins cannot be used
at the same time unless providing a scope.

```ts twoslash [vue-macros.config.ts]
import { defineConfig } from 'vue-macros'
export default defineConfig({
  exportExpose: {
    include: ['**/export-expose/**'],
  },
  exportProps: {
    include: ['**/export-props/**'],
  },
  exportRender: {
    include: ['**/export-render/**'],
  },
})
```

***

:tada: Congratulations! You have successfully set up Vue Macros.

To learn more about the macros, please visit [All Macros](/macros/) :laughing:.

---

---
url: /macros/chain-call.md
---
# chainCall&#x20;

Extends `defineProps`, support call `withDefaults` as a chain.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    |     :question:     |
|    Vue 2     |     :question:     |
|  TypeScript  | :white\_check\_mark: |
| Volar Plugin |        :x:         |

::: tip

* `chainCall` does not support `definePropsRefs`
* To fully support TypeScript, you need to import this macro from `vue-macros/macros`.

:::

## Basic Usage

```vue
<script setup lang="ts">
const props = defineProps<{
  foo?: string
  bar?: number[]
  baz?: boolean
}>().withDefaults({
  foo: '111',
  bar: () => [1, 2, 3],
})
</script>
```

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const props = withDefaults(
  defineProps<{
    foo?: string
    bar?: number[]
    baz?: boolean
  }>(),
  {
    foo: '111',
    bar: () => [1, 2, 3],
  },
)
</script>
```

:::

Also support [props destructuring](../features/reactivity-transform.md) and JSX:

```vue
<script setup lang="ts">
const { foo } = defineProps<{ foo: string }>().withDefaults({
  foo: '111',
})
</script>
```

## TypeScript

To fully support TypeScript, you need to import this macro from `vue-macros/macros` with specific syntax.

```vue twoslash
<script setup lang="ts">
import { defineProps } from 'vue-macros/macros' with { type: 'macro' }

defineProps<{
  /* ... */
}>().withDefaults({
  /* ... */
})
// ✅ type safe
</script>
```

Works without import assertion, but tsc will report an error:

```ts twoslash
// @errors: 2339
defineProps<{
  /* ... */
}>().withDefaults({
  /* ... */
})
```

---

---
url: /guide/configurations.md
---
# Configurations

## Plugin Options

All features are enabled by default except the following.

#### Disabled by Default

* `exportExpose`
* `exportProps`
* `exportRender`
* `setupSFC`
* `booleanProp`
* `shortBind`
* `defineStyleX`

#### Disabled by Default when Vue >= 3.3

* `defineOptions`
* `defineSlots`
* `hoistStatic`
* `shortEmits`

You can re-enable them by setting the option to `true`.

```ts twoslash [vue-macros.config.(ts,js,json)]
import { defineConfig } from 'vue-macros'
export default defineConfig({
  root: '/your-project-path',

  /**
   * Vue version, 2 or 3.
   *
   * optional, detecting automatically.
   */
  version: 3,

  /** Defaults to true */
  defineModels: {
    // ...
  },

  // Enable features
  defineOptions: true,

  // Disable features
  hoistStatic: false,

  // ... more features
})
```

Refer to the macros and features page for available options.

---

---
url: /macros/define-emit.md
---
# defineEmit&#x20;

Declare single emit one by one using `defineEmit`.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     | :white\_check\_mark: |
|  TypeScript  | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

::: warning

`defineEmit` can not be used with `defineEmits` at same time

:::

## API Reference

```ts
defineEmit<T>(emitName)
defineEmit<T>(emitName, validator)

// emitName parameter can be optional,
// and will be inferred from variable name
const emitName = defineEmit<T>()
```

## Basic Usage

```vue twoslash
<script setup>
// Declare emit
const increment = defineEmit('increment')
// Infer emit name from variable name
const change = defineEmit()
// emit event
increment()
</script>
```

## With Validation

```vue twoslash
<script setup>
// Declare event with validation
const increment = defineEmit('increment', (value) => value < 20)
</script>
```

## TypeScript

```vue twoslash
<script setup lang="ts">
const increment = defineEmit('increment', (value: number) => value < 20)
const decrement = defineEmit<[value: number]>()

increment(2) // pass
// @errors: 2345
increment('2') // TS type error
</script>
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "defineEmit": true,
    },
  },
}
```

---

---
url: /volar/define-generic.md
---
# defineGeneric&#x20;

Declare single generic one by one using `DefineGeneric`.

> Especially useful for `setup-sfc`.

|   Features   |     Supported      |
| :----------: | :----------------: |
| Volar Plugin | :white\_check\_mark: |

## Basic Usage

::: code-group

```vue [App.vue] twoslash
<script setup lang="ts">
// @errors: 2322
defineOptions({
  name: 'App',
})

type T = DefineGeneric<number>

defineProps<{
  foo: T
}>()
</script>

<template>
  <App foo="1" />
</template>
```

:::

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-models.md
---
# defineModels&#x20;

Declaring and mutate `v-model` props as the same as normal variable using the `defineModels`.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

## Options

```ts
VueMacros({
  defineModels: {
    /**
     * Unified mode, only works for Vue 2
     *
     * Converts `modelValue` to `value`
     */
    unified: false,
  },
})
```

## Basic Usage

Requires [`@vueuse/core`](https://www.npmjs.com/package/@vueuse/core), install it by yourself before using.

```vue twoslash
<script setup lang="ts">
const { modelValue, count } = defineModels<{
  modelValue: string
  count: number
}>()

console.log(modelValue.value)
modelValue.value = 'newValue'
</script>
```

::: warning ❌ Object declaring is not supported.

```vue
<script setup lang="ts">
const { modelValue } = defineModels({
  modelValue: String,
})
</script>
```

:::

## With Model Options

```vue twoslash 3-6
<script setup lang="ts">
const { modelValue } = defineModels<{
  modelValue: ModelOptions<
    string,
    { defaultValue: 'something'; deep: true; passive: true }
  >
}>()
</script>
```

## With Reactivity Transform

::: warning

Assignment expression is only supported in `<script setup>` block. In other words invalid in `<template>`.

:::

[`@vueuse/core`](https://www.npmjs.com/package/@vueuse/core) is not required.

```vue twoslash {7-9}
<script setup lang="ts">
let { modelValue, count } = $defineModels<{
  modelValue: string
  count: number
}>()

console.log(modelValue)
modelValue = 'newValue'
count++
</script>
```

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const { modelValue, count } = defineProps<{
  modelValue: string
  count: number
}>()

const emit = defineEmits<{
  (evt: 'update:modelValue', value: string): void
  (evt: 'update:count', value: number): void
}>()

console.log(modelValue)
emit('update:modelValue', 'newValue')
emit('update:count', count + 1)
</script>
```

:::

## Volar Configuration

```jsonc {4,6-9} [tsconfig.json]
{
  "vueCompilerOptions": {
    "target": 3, // or 2.7 for Vue 2
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "defineModels": {
        // Only works when target is 2.7.
        "unified": true,
      },
    },
  },
}
```

---

---
url: /macros/define-options.md
---
# defineOptions&#x20;

Options API can be declared using the `defineOptions` in `<script setup>`, specifically to be able to set `name`, `props`, `emits`, and `render` inside of one function.

For Vue >= 3.3, this feature will be turned off by default.

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Nuxt 3   | :white\_check\_mark: |
|   Vue 2    | :white\_check\_mark: |
| TypeScript | :white\_check\_mark: |

## Installation Standalone Version

if you need `defineOptions` feature only, the standalone version is more appropriate for you.

### Installation

::: code-group

```bash [npm]
npm i -D unplugin-vue-define-options @vue-macros/volar
```

```bash [yarn]
yarn add -D unplugin-vue-define-options @vue-macros/volar
```

```bash [pnpm]
pnpm add -D unplugin-vue-define-options @vue-macros/volar
```

:::

::: code-group

```ts [Vite]
// vite.config.ts
import DefineOptions from 'unplugin-vue-define-options/vite'

export default defineConfig({
  plugins: [DefineOptions()],
})
```

```ts [Rollup]
// rollup.config.js
import DefineOptions from 'unplugin-vue-define-options/rollup'

export default {
  plugins: [DefineOptions()],
}
```

```js [esbuild]
// esbuild.config.js
import { build } from 'esbuild'

build({
  plugins: [require('unplugin-vue-define-options/esbuild')()],
})
```

```js [Webpack]
// webpack.config.js
module.exports = {
  /* ... */
  plugins: [require('unplugin-vue-define-options/webpack')()],
}
```

:::

### TypeScript Support

```json [tsconfig.json]
{
  "compilerOptions": {
    // ...
    "types": ["unplugin-vue-define-options/macros-global" /* ... */]
  }
}
```

## Basic Usage

```vue twoslash {3-4}
<script setup lang="ts">
defineOptions({
  name: 'Foo',
  inheritAttrs: false,
})

defineProps<{
  foo: number
}>()
</script>

<template>
  <Foo :foo="1" />
</template>
```

::: details Compiled Code

```vue twoslash
<script lang="ts">
export default {
  name: 'Foo',
  inheritAttrs: false,
}
</script>

<script setup lang="ts">
defineProps<{
  foo: number
}>()
</script>

<template>
  <Foo :foo="1" />
</template>
```

:::

## JSX in `<script setup>`

```vue twoslash {3-5}
<script setup lang="tsx">
defineOptions({
  render() {
    return <h1>Hello World</h1>
  },
})
</script>
```

::: details Compiled Code

```vue
<script lang="tsx">
export default {
  render() {
    return <h1>Hello World</h1>
  },
}
</script>
```

:::

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-prop.md
---
# defineProp&#x20;

Declare single prop one by one using `defineProp`.

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|       Nuxt 3       | :white\_check\_mark: |
|       Vue 2        | :white\_check\_mark: |
| TypeScript / Volar | :white\_check\_mark: |

::: warning

`defineProp` can not be used in the same file as type-declared `defineProps`.

:::

## Configuration

```ts
VueMacros({
  defineProp: {
    /**
     * 'kevinEdition' | 'johnsonEdition'
     * @default 'kevinEdition'
     */
    edition: 'kevinEdition',
  },
})
```

## Kevin's Edition (Default)

### API Reference

```ts
defineProp<T>(propName)
defineProp<T>(propName, options)

// propName parameter can be optional,
// and will be inferred from variable name
const propName = defineProp<T>()
```

### Basic Usage

```vue twoslash
<script setup lang="ts">
// Declare prop
const count = defineProp('count')

// Infer prop name from variable name
const value = defineProp()

// access prop value
console.log(count.value)
</script>
```

### With Options

```vue twoslash
<script setup lang="ts">
// Declare prop with options
const count = defineProp('count', {
  type: Number,
  required: true,
  default: 0,
  validator: (value: number) => value < 20,
})
</script>
```

### TypeScript

```vue twoslash
<script setup lang="ts">
// Declare prop of type number and infer prop name from variable name
const count = defineProp<number>()
count.value

// Declare prop of TS type boolean with default value
const disabled = defineProp<boolean>('disabled', { default: true })
disabled.value
</script>
```

### With Reactivity Transform

```vue twoslash
<script setup lang="ts">
const foo = $defineProp<string>('foo')

const bar = $(defineProp('bar', { default: 'bar' }))
</script>
```

## Johnson's Edition

### API Reference

```ts
// the prop name will be inferred from variable name
const propName = defineProp<T>()
const propName = defineProp<T>(defaultValue)
const propName = defineProp<T>(defaultValue, required)
const propName = defineProp<T>(defaultValue, required, rest)
```

### Basic Usage

```vue
<script setup lang="ts">
// declare prop `count` with default value `0`
const count = defineProp(0)

// declare required prop `disabled`
const disabled = defineProp(undefined, true)

// access prop value
console.log(count.value, disabled.value)
</script>
```

### With Options

```vue
<script setup lang="ts">
// Declare prop with options
const count = defineProp(0, false, {
  type: Number,
  validator: (value: number) => value < 20,
})
</script>
```

### TypeScript

```vue
<script setup lang="ts">
const count = defineProp<number>()
count.value

// Declare prop of TS type boolean with default value
const disabled = defineProp<boolean>(true)
disabled.value
</script>
```

### With Reactivity Transform

```vue
<script setup lang="ts">
const foo = $defineProp<number>()

const bar = $(defineProp(0, true))
</script>
```

### Volar Configuration

```jsonc {3,7} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "defineProp": {
        // "kevinEdition" | "johnsonEdition"
        "edition": "kevinEdition",
      },
    },
  },
}
```

---

---
url: /macros/define-props.md
---
# defineProps&#x20;

Correct types of destructured props using `$defineProps`.

See also [Vue issue](https://github.com/vuejs/core/issues/6876), [Reactivity Transform RFC](https://github.com/vuejs/rfcs/blob/reactivity-transform/active-rfcs/0000-reactivity-transform.md#defineprops-destructure-details).

|         Features          |     Supported      |
| :-----------------------: | :----------------: |
|           Vue 3           | :white\_check\_mark: |
|          Nuxt 3           | :white\_check\_mark: |
|           Vue 2           | :white\_check\_mark: |
| TypeScript / Volar Plugin | :white\_check\_mark: |

::: warning

[Reactivity Transform](../features/reactivity-transform.md) is required. You should enable it first.

:::

## Basic Usage

```vue twoslash
<script setup lang="ts">
const { foo } = $defineProps<{
  //     ^?
  foo: string[]
}>()

const fooRef = $(foo)
//     ^?
</script>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-props-refs.md
---
# definePropsRefs&#x20;

Returns refs from `defineProps` instead of a reactive object. It can be destructured without losing reactivity.

`toRefs(defineProps())` => `definePropsRefs()`

|         Features          |     Supported      |
| :-----------------------: | :----------------: |
|           Vue 3           | :white\_check\_mark: |
|          Nuxt 3           | :white\_check\_mark: |
|           Vue 2           | :white\_check\_mark: |
| TypeScript / Volar Plugin | :white\_check\_mark: |

## Basic Usage

```vue twoslash {2-3,8}
<script setup lang="ts">
// ✅ won't lose reactivity with destructuring
const { foo, bar } = definePropsRefs<{
  foo: string
  bar: number
}>()

console.log(foo.value, bar.value)
//           ^?
</script>
```

## With Default Value

```vue twoslash {2-3,8}
<script setup lang="ts">
import { withDefaults } from 'vue-macros/macros' with { type: 'macro' }

const { foo } = withDefaults(
  definePropsRefs<{
    foo?: string
  }>(),
  { foo: 'test' },
)

console.log(foo.value)
//           ^?
</script>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-render.md
---
# defineRender&#x20;

Defining render function in `<script setup>` using the `defineRender`.

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Nuxt 3   | :white\_check\_mark: |
|   Vue 2    | :white\_check\_mark: |
| TypeScript | :white\_check\_mark: |

We need more feedback on [RFC Discussion](https://github.com/vuejs/rfcs/discussions/585)!

## Basic Usage

```vue twoslash
<script setup lang="tsx">
// JSX passed directly
defineRender(
  <div>
    <span>Hello</span>
  </div>,
)

// Or using render function
defineRender(() => {
  return (
    <div>
      <h1>Hello World</h1>
    </div>
  )
})
</script>
```

---

---
url: /macros/define-slots.md
---
# defineSlots&#x20;

Declaring type of SFC slots in `<script setup>` using the `defineSlots`.

For Vue >= 3.3, this feature will be turned off by default.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |
|    Vue 2     |        :x:         |

## Basic Usage

### Short Syntax

```vue twoslash
<script setup lang="ts">
defineSlots<{
  // slot name
  title: {
    // scoped slot
    foo: 'bar' | boolean
  }
}>()
</script>
```

### Full Syntax (Official Version)

```vue twoslash
<script setup lang="ts">
defineSlots<{
  title: (scope: { text: string }) => any
}>()
</script>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-stylex.md
---
# defineStyleX&#x20;

Define and consume [StyleX](https://stylexjs.com/) styles in `<script setup>`.

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|       Nuxt 3       | :white\_check\_mark: |
| TypeScript / Volar | :white\_check\_mark: |
|       Vue 2        | :white\_check\_mark: |

## Setup

To use StyleX, you should install and configure StyleX first. The steps could change, you may want to check the [official document](https://stylexjs.com/) and the [document of StyleX bundler integrations](https://stylexjs.com/docs/learn/ecosystem/#third-party-bundler-integrations) for the latest information.

### Vite

```sh
pnpm add @stylexjs/stylex @stylex-extend/core @stylex-extend/vite -D
```

```ts [vite.config.ts] {1,13}
import { stylex } from '@stylex-extend/vite'
import Vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
import VueMacros from 'vue-macros/vite'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue(),
      },
    }),
    stylex(), // Must be placed after Vue Macros
  ],
})
```

```ts [main.ts] {2}
// import StyleX stylesheet, according to https://nonzzz.github.io/stylex-extend/integrations/vite
import 'virtual:stylex.css'
```

## Basic Usage

```vue [App.vue] twoslash
<script setup lang="ts">
const styles = defineStyleX({
  red: { color: 'red' },
})

// ...
// ---cut-start---
declare const vStylex: any
// ---cut-end---
</script>

<template>
  <p v-stylex="styles.red">Red</p>
</template>
```

:::details Compiled Code (with some simplifications)

```vue [App.vue] twoslash
<script lang="ts">
const styles = _stylex_create({
  red: { color: 'red' },
})
</script>

<script setup lang="ts">
import {
  create as _stylex_create,
  props as _stylex_props,
} from '@stylexjs/stylex'
// virtual module to provide runtime code
// ---cut-start---
// @ts-ignore
// ---cut-end---
import stylex_attrs from '/vue-macros/define-stylex/stylex-attrs'

// ...
</script>

<template>
  <p v-bind="stylex_attrs(_stylex_props(styles.red))">Red</p>
</template>
```

:::

## Conditional Styles

Optional and multiple rules are supported.

```vue [App.vue] twoslash
<script setup lang="ts">
defineProps<{ bold?: boolean }>()

const styles = defineStyleX({
  red: { color: 'red' },
  bold: { fontWeight: 'bold' },
})
// ---cut-start---
declare const vStylex: any
// ---cut-end---
</script>

<template>
  <span v-stylex="(styles.red, bold && styles.bold)">Red</span>
</template>
```

:::details Compiled Code (with some simplifications)

```vue [App.vue] twoslash
<script lang="ts">
const styles = _stylex_create({
  red: { color: 'red' },
  bold: { fontWeight: 'bold' },
})
</script>

<script setup lang="ts">
import {
  create as _stylex_create,
  props as _stylex_props,
} from '@stylexjs/stylex'
// ---cut-start---
// @ts-ignore
// ---cut-end---
import stylex_attrs from '/vue-macros/define-stylex/stylex-attrs'

defineProps<{ bold?: boolean }>()
</script>

<template>
  <span v-bind="stylex_attrs(_stylex_props(styles.red, bold && styles.bold))"
    >Red</span
  >
</template>
```

:::

---

---
url: /features/export-expose.md
---
# exportExpose&#x20;

Transform export statement as `defineExpose` params in Vue SFC `script-setup`.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    |         ?          |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

## Usage

Support these syntaxes:

* local variable/function/class
* export with alias
* export from other file
* namespace export
* rename export

### 1. local variable/function/class

```vue twoslash
<script setup lang="ts">
export const foo: string = 'foo'
export const bar = 10
export let baz: string | undefined
export var qux = fn()
// @errors: 2448 2454 2695
export const { a, b, c } = { a: 1, b: 2, c: 3 }

export function fn() {}
export class A {}
</script>
```

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const foo: string = 'foo'
const bar = 10
let baz: string | undefined
const qux = fn()
const { a, b, c } = { a: 1, b: 2, c: 3 }

function fn() {}
class A {}

defineExpose({
  foo,
  bar,
  baz,
  qux,
  a,
  b,
  c,
  fn,
  A,
})
</script>
```

:::

### 2. export with alias

```vue twoslash
<script setup lang="ts">
const foo = ''

export { foo as foo1 }
</script>
```

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const foo = 'foo'

defineExpose({
  foo1: foo,
})
</script>
```

:::

### 3. export from other file

::: code-group

```vue [App.vue] twoslash
<script setup lang="ts">
// #region export-file
const foo = 'foo'
type Foo = string

export { foo, type Foo }
// #endregion export-file
// ---cut---
// @noErrors
export { foo as bar, foo, type Foo } from './types'
</script>
```

<<< ./export-expose.md#export-file{ts} \[types.ts]

:::

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const __MACROS_expose_0 = 'foo'
const __MACROS_expose_1 = 'foo'
type Foo = string
// ---cut---
// @noErrors
import {
  foo as __MACROS_expose_0,
  foo as __MACROS_expose_1,
  type Foo,
} from './types'
defineExpose({
  foo: __MACROS_expose_0,
  bar: __MACROS_expose_1,
})
</script>
```

:::

### 4. namespace export

::: code-group

```vue [App.vue] twoslash
<script setup lang="ts">
const foo = { foo: 'foo' }
// ---cut---
// @noErrors
export * as foo from './types'
</script>
```

```ts [types.ts]
export const foo = 'foo'
```

:::

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const __MACROS_expose_0 = {
  foo: 'foo',
}
// ---cut---
// @noErrors
import * as __MACROS_expose_0 from './types'
defineExpose({
  foo: __MACROS_expose_0,
})
</script>
```

:::

### 5. rename export

```vue
<script setup lang="ts">
const foo = 1
const bar = 1

export { foo } from './types'
export * as bar from './types'
</script>
```

::: details Compiled Code

```vue
<script setup lang="ts">
import { foo as __MACROS_expose_0 } from './types'
import * as __MACROS_expose_1 from './types'

const foo = 1
const bar = 1
defineExpose({
  foo: __MACROS_expose_0,
  bar: __MACROS_expose_1,
})
</script>
```

:::

## Limitations

Currently does't support these following cases:

```ts
// 1. export all ❌
export * from '../types'

// 2. export default ❌
const a = 'a'
export default a
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "exportExpose": true,
    },
  },
}
```

---

---
url: /features/export-props.md
---
# exportProps&#x20;

[Svelte-like Declaring props](https://svelte.dev/docs#component-format-script-1-export-creates-a-component-prop) for Vue.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    |     :question:     |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

## Pre-requisite

[Reactivity Transform](./reactivity-transform.md) is required to use this feature, but it is enabled by default in Vue Macros.

`export let` will be changed to `defineModel`, which is supported in Vue 3.4+.

## Usage

Using export syntax to declare props.

```vue twoslash
<script setup lang="ts">
export let foo: string
export const bar: number = 1 // with default value
</script>
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "exportProps": true,
    },
  },
}
```

---

---
url: /features/export-render.md
---
# exportRender&#x20;

Transform the default export statement, in `<script setup>` of Vue SFC, as a component render function.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    |     :question:     |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

::: tip

This feature depends on `defineRender`, and make sure `defineRender` is not disabled.

:::

## Usage

```vue
<script setup lang="tsx">
// JSX passed directly
export default <div>ok</div>

// Or using render function
export default () => <div>ok</div>
</script>
```

## Volar Configuration

```jsonc {3,7} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "exportRender": true,
    },
  },
}
```

---

---
url: /guide/getting-started.md
---
# Getting Started

Vue Macros is a library that implements unofficial proposals and ideas for Vue,
exploring and extending its features and syntax.

We assume you are already familiar with the basic usages of Vue before you continue.

## Requirements

* Node.js `>= v20.19.0`.
* Vue `>= v2.7` or Vue `>= v3.0`.
  * Some features need Vue `>= v3.2.25`.
* VSCode extension [Vue - Official](https://marketplace.visualstudio.com/items?itemName=Vue.volar) and `vue-tsc` are v{{ version }}
  * Vue Macros will continue to adapt to the latest version as soon as possible, older versions may not be supported.

::: warning
WebStorm is not supported.
:::

## Creating a Vue Macros Project

### Installation

::: code-group

```bash [npm]
npm i -g @vue-macros/cli
```

```bash [yarn]
yarn global add @vue-macros/cli
```

```bash [pnpm]
pnpm add -g @vue-macros/cli
```

:::

This command will install [@vue-macros/cli](https://github.com/vue-macros/vue-macros-cli), the official Vue Macros scaffolding tool.

### Initialization

::: code-group

```bash [npm]
npm create vite@latest my-vue-macros -- --template vue-ts
cd my-vue-macros
vue-macros init
```

```bash [yarn]
yarn create vite my-vue-macros --template vue-ts
cd my-vue-macros
vue-macros init
```

```bash [pnpm]
pnpm create vite my-vue-macros --template vue-ts
cd my-vue-macros
vue-macros init
```

You will be presented with prompts for several optional experimental features.

:::

## Templates

* [Vite](https://github.com/vue-macros/vite)
* [Nuxt](https://github.com/vue-macros/nuxt)
* [Rsbuild](https://github.com/vue-macros/vue3-rsbuild)

🌟 More templates are welcome!

## Nuxt Integration

If you're using [Nuxt](https://nuxt.com/), read the [Nuxt Integration](./nuxt-integration.md).

## Bundler Integrations

If you're using [Vite](https://vitejs.dev/), [Rollup](https://rollupjs.org/), [esbuild](https://esbuild.github.io/), [Webpack](https://webpack.js.org/), or [Rspack](https://www.rspack.dev/), read the [Bundler Integration](./bundler-integration.md).

---

---
url: /features/hoist-static.md
---
# hoistStatic&#x20;

With enabling `hoistStatic`, constants declared in macros of `<script setup>` can be referenced.

For Vue >= 3.3, this feature will be turned off by default.

| Features |     Supported      |
| :------: | :----------------: |
|  Vue 3   | :white\_check\_mark: |
|  Nuxt 3  | :white\_check\_mark: |
|  Vue 2   | :white\_check\_mark: |

## Basic Usage

```vue twoslash
<script setup lang="ts">
const name = 'AppFoo'
defineOptions({
  name,
})
</script>
```

::: details Compiled Code

```vue
<script lang="ts">
const name = 'AppFoo'
export default {
  name,
}
</script>
```

:::

## Magic Comments

```vue
<script setup lang="ts">
// A value that's even not a constant
const name = /* hoist-static */ fn()
defineOptions({
  name,
})
</script>
```

::: details Compiled Code

```vue
<script lang="ts">
const name = fn()
export default {
  name,
}
</script>
```

:::

---

---
url: /features/jsx-directive.md
---
# jsxDirective&#x20;

Vue built-in directives for JSX.

|  Directive  |       Vue 3        |       Vue 2        |       Volar        |
| :---------: | :----------------: | :----------------: | :----------------: |
|   `v-if`    | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
| `v-else-if` | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|  `v-else`   | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|   `v-for`   | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|   `v-on`    | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|  `v-slot`   | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|  `v-html`   | :white\_check\_mark: | :white\_check\_mark: |         /          |
|  `v-once`   | :white\_check\_mark: |        :x:         |         /          |
|  `v-memo`   | :white\_check\_mark: |        :x:         |         /          |

## Options

```ts
interface Options {
  /**
   * @default 'v-'
   */
  prefix?: string
  /**
   * @default 'vue'
   */
  lib?: 'vue' | 'react' | 'preact' | 'solid' | string
}
```

## Usage

### `v-if`, `v-else-if`, `v-else`

```vue twoslash
<script setup lang="tsx">
const { foo } = defineProps<{
  foo: number
}>()

// ---cut-start---
// prettier-ignore
// ---cut-end---
export default () => (
  <>
    <div v-if={foo === 0}>{foo}</div>

    <div v-else-if={foo === 1}>{foo}</div>
    //                          ^?

    <div v-else>{foo}</div>
    //           ^?
  </>
)
</script>
```

### `v-for`

```vue twoslash
<script setup lang="tsx">
export default () => (
  <div v-for={(item, index) in 4} key={index}>
    {item}
  </div>
)
</script>
```

### `v-slot`

::: code-group

```vue [App.vue] twoslash
<script lang="tsx" setup>
// #region v-slot
import type { FunctionalComponent } from 'vue'

export const Comp: FunctionalComponent<
  {},
  {},
  {
    default: () => any
    slot: (scope: { bar: number }) => any
    slots: (scope: { baz: boolean }) => any
  }
> = () => <div />
// #endregion v-slot
// ---cut---
// @noErrors
import { Comp } from './Comp.tsx'

// ---cut-start---
// prettier-ignore
// ---cut-end---
export default () => (
  <Comp>
    default slot...
    <template v-slot:slot={{ bar }}>
      //              ^|
      {bar}
    </template>
  </Comp>
)
</script>
```

<<< ./jsx-directive.md#v-slot{tsx} \[Child.tsx]

:::

### `v-on`

::: warning

`v-on` only supports binding to an object of event / listener pairs without an argument.

:::

```tsx
<form v-on={{ submit }} />
```

## Dynamic Arguments

It is also possible to use a variable in a directive argument by wrapping it with a pair of `


  
  
  
  
  vue-macros.dev | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


  :

`v-model`

::: code-group

```vue [App.vue] twoslash
<script setup lang="tsx">
// ---cut-start---
// #region v-model
import { ref, type FunctionalComponent } from 'vue'

export const Comp: FunctionalComponent<
  {
    model: string
    models: string[]
  },
  {
    'update:model': [value: string]
    'update:models': [value: string[]]
  }
> = () => <div />
// #endregion v-model
// ---cut-end---
// @noErrors
import { Comp } from './Comp.tsx'

const name = ref('model')
const model = defineModel<string>()

export default () => (
  <Comp
    v-model:$name$={model.value}
    v-model:model={model.value}
    //       ^|
  />
)
</script>
```

<<< ./jsx-directive.md#v-model{tsx} \[Comp.tsx]

:::

`v-slot`

::: code-group

```vue [App.vue] twoslash
<script setup lang="tsx">
// ---cut-start---
// #region v-slot-dynamic
import type { FunctionalComponent } from 'vue'

export const Comp: FunctionalComponent<
  {},
  {},
  {
    default: (scope: { foo: string }) => any
    title: (scope: { bar: number }) => any
  }
> = () => <div />
// #endregion v-slot-dynamic
// ---cut-end---
// @noErrors
import { Comp } from './Comp.tsx'

const slots = defineSlots<{
  default: (scope: { foo: string }) => any
  title: (scope: { bar: number }) => any
}>()

// ---cut-start---
// prettier-ignore
// ---cut-end---
export default () => (
  <Comp>
    <template v-for={(Slot, name) in slots} v-slot:$name$={scope}>
      //                                             ^?
      <Slot {...scope} />
    </template>
  </Comp>
)
</script>
```

<<< ./jsx-directive.md#v-slot-dynamic{tsx} \[Comp.tsx]

:::

## Modifiers

Modifiers are special postfixes denoted by a `_`, which indicate that a directive should be bound in some special way.

```tsx
<form onSubmit_prevent>
  <input v-model_number={value} />
</form>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /volar/jsx-ref.md
---
# jsxRef&#x20;

Automatically infer type for `useRef`.

| Features |     Supported      |
| :------: | :----------------: |
|  Volar   | :white\_check\_mark: |

## Setup Auto Import

::: code-group

```ts [vite.config.ts]
import AutoImport from 'unplugin-auto-import/vite'

export default defineConfig({
  plugins: [
    AutoImport({
      imports: [
        {
          from: 'vue',
          imports: [['shallowRef', 'useRef']],
        },
      ],
    }),
  ],
})
```

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  imports: {
    presets: [
      {
        from: 'vue',
        imports: [['shallowRef', 'useRef']],
      },
    ],
  },
})
```

:::

## Basic Usage

::: code-group

```vue [App.vue] twoslash
<script lang="tsx">
// #region comp
import { defineComponent } from 'vue'

export const Comp = defineComponent({
  setup() {
    return { foo: 1 }
  },
})
// #endregion comp
// ---cut---
import { useRef } from 'vue-macros/runtime'
// Or import { shallowRef as useRef } from 'vue'
// @noErrors
import { Comp } from './Comp.ts'

export default defineComponent(() => {
  const comp = useRef()
  comp.value?.foo
  //           ^?

  return () => (
    <>
      <Comp ref={comp} />
    </>
  )
})
</script>
```

<<< ./jsx-ref.md#comp{ts} \[Comp.ts]

:::

## Volar Configuration

```jsonc [tsconfig.json] {3,6}
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "jsxRef": {
        "alias": ["useRef"],
      },
    },
  },
}
```

---

---
url: /guide/migration-v3.md
---
# Migration from v2 to v3

## Unified Version Management

Initially, we used [`changesets`](https://github.com/changesets/changesets) to
manage the versions of all packages in the monorepo. However, after two years of experimentation,
we decided to adopt a single-version strategy in v3,
where all sub-packages share the same version number, similar to Vue and Babel.
This decision stemmed from our observation that when a sub-package underwent a major change or minor update,
the version number of the main package did not adequately reflect these changes.

For example, when `@vue-macros/define-prop` introduced a breaking change,
how should `unplugin-vue-macros` release a new version?
Should it be a minor or a patch release? When users updated `unplugin-vue-macros`,
they couldn’t easily determine whether the update was due to changes in `@vue-macros/define-prop`.

Therefore, after Anthony proposed [Epoch Semantic Versioning](https://antfu.me/posts/epoch-semver),
we decided to adopt a more frequent major version update strategy,
with all packages sharing the same version number and maintaining a single unified changelog.

## Main Package Rename

We have renamed the main package from `unplugin-vue-macros` to **`vue-macros`**.
After the official release of v3, `unplugin-vue-macros` will be marked as deprecated.

As a result, you will need to update your `package.json` and the import statements for Vue Macros:

```diff
 // package.json
 {
   "devDependencies": {
-    "unplugin-vue-macros": "^2.14.5"
+    "vue-macros": "^3.0.0"
   }
 }
```

```diff
- import { $ref } from 'unplugin-vue-macros/macros'
+ import { $ref } from 'vue-macros/macros'

- import VueMacros from 'unplugin-vue-macros/vite'
+ import VueMacros from 'vue-macros/vite'
```

## Dropping Vue 2 Support

Vue 2 reached its end of life (EOL) at the end of 2023, so we have decided to drop support for Vue 2 in v3.
If you are still using Vue 2, we recommend continuing with v2 or
considering our [paid support plan](https://github.com/vue-macros/vue-macros/issues/373).

## Node.js Compatibility Changes

In v3, we have dropped support for Node.js versions below 20.19.
This means the minimum Node.js version requirement for v3 is `20.19.0`.
Additionally, we have removed CommonJS (CJS) outputs and now only provide ECMAScript modules (ESM).

## Dropping Webpack 4 Support

Since Webpack 4 cannot run in Node.js 18 or later environments,
we have also dropped support for Webpack 4 and Vue CLI 4.
We recommend upgrading to modern build tools like Vite or Rspack.

---

---
url: /features/named-template.md
---
# namedTemplate&#x20;

::: warning

Not actively maintained now. Try [createReusableTemplate](https://vueuse.org/core/createReusableTemplate/) instead.

:::

With enabling `namedTemplate`, `<template>` can be referenced like a variable.

Sometimes we need to reverse the order of the very simple components, and don't want to give the features of Vue template up and use JSX/TSX. Then this feature is much helpful.

If you support this feature, you can go to [the discussion](https://github.com/vuejs/core/discussions/6898) and hit like :+1: or comment.

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|      Vue 3.3       |        :x:         |
|       Nuxt 3       |        :x:         |
|       Vue 2        |        :x:         |
| TypeScript / Volar |        :x:         |

## Basic Usage

```vue {5-7,10-12,16-18}
<script setup>
const pager = 'top'
</script>

<template name="pager">
  <span>This is pager</span>
</template>

<template>
  <template v-if="pager === 'top'">
    <template is="pager" />
  </template>

  <span>Here is data table</span>

  <template v-if="pager === 'bottom'">
    <template is="pager" />
  </template>
</template>
```

## Known Usage

* TypeScript / Volar support is not yet completed.

---

---
url: /features/reactivity-transform.md
---
# Reactivity Transform&#x20;

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|       Nuxt 3       | :white\_check\_mark: |
|       Vue 2        | :white\_check\_mark: |
| TypeScript / Volar | :white\_check\_mark: |

## Installation Standalone Version

if you need Reactivity Transform feature only, the standalone version is more appropriate for you.

### Installation

::: code-group

```bash [npm]
npm i -D @vue-macros/reactivity-transform
```

```bash [yarn]
yarn add -D @vue-macros/reactivity-transform
```

```bash [pnpm]
pnpm add -D @vue-macros/reactivity-transform
```

:::

::: code-group

```ts [Vite]
// vite.config.ts
import ReactivityTransform from '@vue-macros/reactivity-transform/vite'

export default defineConfig({
  plugins: [ReactivityTransform()],
})
```

```ts [Rollup]
// rollup.config.js
import ReactivityTransform from '@vue-macros/reactivity-transform/rollup'

export default {
  plugins: [ReactivityTransform()],
}
```

```js [esbuild]
// esbuild.config.js
import { build } from 'esbuild'

build({
  plugins: [require('@vue-macros/reactivity-transform/esbuild')()],
})
```

```js [Webpack]
// webpack.config.js
module.exports = {
  /* ... */
  plugins: [require('@vue-macros/reactivity-transform/webpack')()],
}
```

:::

### TypeScript Support

```json [tsconfig.json]
{
  "compilerOptions": {
    // ...
    "types": ["@vue-macros/reactivity-transform/macros-global" /* ... */]
  }
}
```

## Refs vs. Reactive Variables {#refs-vs-reactive-variables}

Ever since the introduction of the Composition API, one of the primary unresolved questions is the use of refs vs. reactive objects. It's easy to lose reactivity when destructuring reactive objects, while it can be cumbersome to use `.value` everywhere when using refs. Also, `.value` is easy to miss if not using a type system.

Reactivity Transform is a compile-time transform that allows us to write code like this:

```vue twoslash
<script setup>
let count = $ref(0)

console.log(count)

function increment() {
  count++
}
</script>

<template>
  <button @click="increment">{{ count }}</button>
</template>
```

The `$ref()` method here is a **compile-time macro**: it is not an actual method that will be called at runtime. Instead, the Vue compiler uses it as a hint to treat the resulting `count` variable as a **reactive variable.**

Reactive variables can be accessed and re-assigned just like normal variables, but these operations are compiled into refs with `.value`. For example, the `<script>` part of the above component is compiled into:

```js{5,8} twoslash
import { ref } from 'vue'

let count = ref(0)

console.log(count.value)

function increment() {
  count.value++
}
```

Every reactivity API that returns refs will have a `


  
  
  
  
  vue-macros.dev | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


  -prefixed macro equivalent. These APIs include:

* [`ref`](https://vuejs.org/api/reactivity-core#ref) -> `$ref`
* [`computed`](https://vuejs.org/api/reactivity-core#computed) -> `$computed`
* [`shallowRef`](https://vuejs.org/api/reactivity-advanced#shallowref) -> `$shallowRef`
* [`customRef`](https://vuejs.org/api/reactivity-advanced#customref) -> `$customRef`
* [`toRef`](https://vuejs.org/api/reactivity-utilities#toref) -> `$toRef`

These macros are globally available and do not need to be imported when Reactivity Transform is enabled, but you can optionally import them from `vue-macros/macros` or `@vue-macros/reactivity-transform/macros-global` if you want to be more explicit:

```js twoslash
import { $ref } from 'vue-macros/macros'
// for standalone version:
// import { $ref } from '@vue-macros/reactivity-transform/macros-global'

const count = $ref(0)
```

## Destructuring with `$()` {#destructuring-with}

It is common for a composition function to return an object of refs, and use destructuring to retrieve these refs. For this purpose, reactivity transform provides the **`$()`** macro:

```js twoslash
import { ref } from 'vue'
function useMouse() {
  return {
    x: ref(0),
    y: ref(0),
  }
}
// ---cut---
const { x, y } = $(useMouse())

console.log(x, y)
```

Compiled output:

```js twoslash
import { ref, toRef } from 'vue'
function useMouse() {
  return {
    x: ref(0),
    y: ref(0),
  }
}
// ---cut---
const __temp = useMouse()
const x = toRef(__temp, 'x')
const y = toRef(__temp, 'y')

console.log(x.value, y.value)
```

Note that if `x` is already a ref, `toRef(__temp, 'x')` will simply return it as-is and no additional ref will be created. If a destructured value is not a ref (e.g. a function), it will still work - the value will be wrapped in a ref so the rest of the code works as expected.

`$()` destructure works on both reactive objects **and** plain objects containing refs.

## Convert Existing Refs to Reactive Variables with `$()` {#convert-existing-refs-to-reactive-variables-with}

In some cases we may have wrapped functions that also return refs. However, the Vue compiler won't be able to know ahead of time that a function is going to return a ref. In such cases, the `$()` macro can also be used to convert any existing refs into reactive variables:

```js twoslash
import { ref } from 'vue'

function myCreateRef() {
  return ref(0)
}

const count = $(myCreateRef())
```

## Reactive Props Destructure {#reactive-props-destructure}

There are two pain points with the current `defineProps()` usage in `<script setup>`:

1. Similar to `.value`, you need to always access props as `props.x` in order to retain reactivity. This means you cannot destructure `defineProps` because the resulting destructured variables are not reactive and will not update.

2. When using the [type-only props declaration](https://vuejs.org/api/sfc-script-setup.html#typescript-only-features), there is no easy way to declare default values for the props. We introduced the `withDefaults()` API for this exact purpose, but it's still clunky to use.

We can address these issues by applying a compile-time transform when `defineProps` is used with destructuring, similar to what we saw earlier with `$()`:

```vue twoslash
<script setup lang="ts">
import { watchEffect } from 'vue'

interface Props {
  msg: string
  count?: number
  foo?: string
}

const {
  msg,
  // default value just works
  count = 1,
  // local aliasing also just works
  // here we are aliasing `props.foo` to `bar`
  foo: bar,
} = defineProps<Props>()

watchEffect(() => {
  // will log whenever the props change
  console.log(msg, count, bar)
})
</script>
```

The above will be compiled into the following runtime declaration equivalent:

```ts twoslash
import { defineComponent, watchEffect } from 'vue'

export default defineComponent({
  props: {
    msg: { type: String, required: true },
    count: { type: Number, default: 1 },
    foo: String,
  },
  setup(props) {
    watchEffect(() => {
      console.log(props.msg, props.count, props.foo)
    })
  },
})
```

## Retaining Reactivity Across Function Boundaries {#retaining-reactivity-across-function-boundaries}

While reactive variables relieve us from having to use `.value` everywhere, it creates an issue of "reactivity loss" when we pass reactive variables across function boundaries. This can happen in two cases:

### Passing into function as argument {#passing-into-function-as-argument}

Given a function that expects a ref as an argument, e.g.:

```ts twoslash
import { watch, type Ref } from 'vue'

function trackChange(x: Ref<number>) {
  watch(x, (x) => {
    console.log('x changed!')
  })
}

const count = $ref(0)
// @errors: 2345
trackChange(count) // doesn't work!
```

The above case will not work as expected because it compiles to:

```ts
const count = ref(0)
trackChange(count.value)
```

Here `count.value` is passed as a number, whereas `trackChange` expects an actual ref. This can be fixed by wrapping `count` with `$()` before passing it:

```diff
let count = $ref(0)
- trackChange(count)
+ trackChange($(count))
```

The above compiles to:

```js
import { ref } from 'vue'

const count = ref(0)
trackChange(count)
```

As we can see, `$()` is a macro that serves as an **escape hint**: reactive variables inside `$()` will not get `.value` appended.

### Returning inside function scope {#returning-inside-function-scope}

Reactivity can also be lost if reactive variables are used directly in a returned expression:

```ts twoslash
function useMouse() {
  const x = $ref(0)
  const y = $ref(0)

  // listen to mousemove...

  // doesn't work!
  return {
    x,
    y,
  }
}
```

The above return statement compiles to:

```ts
return {
  x: x.value,
  y: y.value,
}
```

In order to retain reactivity, we should be returning the actual refs, not the current value at return time.

Again, we can use `$()` to fix this. In this case, `$()` can be used directly on the returned object - any reference to reactive variables inside the `$()` call will retain the reference to their underlying refs:

```ts twoslash
function useMouse() {
  const x = $ref(0)
  const y = $ref(0)

  // listen to mousemove...

  // fixed
  return $({
    x,
    y,
  })
}
```

### Using `$()` on destructured props {#using-on-destructured-props}

`$()` works on destructured props since they are reactive variables as well. The compiler will convert it with `toRef` for efficiency:

```vue twoslash
<script setup lang="ts">
import type { Ref } from 'vue'
function passAsRef(count: Ref<number>) {
  return count
}
// ---cut---
const { count } = defineProps<{ count: number }>()

passAsRef($(count))
</script>
```

compiles to:

```ts twoslash
import { defineComponent, toRef, type Ref } from 'vue'
function passAsRef(count: Ref<number>) {
  return count
}
// ---cut---
export default defineComponent({
  props: {
    count: { type: Number, required: true },
  },
  setup(props) {
    const __props_count = toRef(props, 'count')
    passAsRef(__props_count)
  },
})
```

## TypeScript Integration  {#typescript-integration}

Vue provides typings for these macros (available globally) and all types will work as expected. There are no incompatibilities with standard TypeScript semantics, so the syntax will work with all existing tooling.

This also means the macros can work in any files where valid JS / TS are allowed - not just inside Vue SFCs.

Since the macros are available globally, their types need to be explicitly referenced (e.g. in a `env.d.ts` file):

```ts [env.d.ts]
/// <reference types="vue-macros/macros-global" />

// or for standalone version:
/// <reference types="@vue-macros/reactivity-transform/macros-global" />
```

When explicitly importing the macros from `vue-macros/macros` or `@vue-macros/reactivity-transform/macros-global`, the type will work without declaring the globals.

---

---
url: /features/script-lang.md
---
# scriptLang&#x20;

Set the default language for `<script>` block.

::: tip
Convert `<script setup>` to `<script setup lang="ts">`.
:::

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

## Options

```ts
interface Options {
  /**
   * @default 'ts'
   */
  defaultLang?: 'ts' | 'tsx' | 'jsx' | string
}
```

## Usage

```vue twoslash
<script setup>
defineProps<{
  foo: string
}>()
</script>
```

## Volar Configuration

```jsonc {3,5-7} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "scriptLang": {
        "defaultLang": "ts",
      },
    },
  },
}
```

---

---
url: /volar/script-sfc.md
---
# scriptSFC&#x20;

Enabled Volar support for `.ts` | `.tsx` files.

|   Features   |     Supported      |
| :----------: | :----------------: |
| Volar Plugin | :white\_check\_mark: |

## Basic Usage

### With `jsxDirective`

::: code-group

```tsx [App.tsx]
export default ({ foo }: { foo: number }) => (
  <div v-if={foo === 1}>{foo}</div>
  //                     ^ will be inferred as 1
)
```

:::

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["@vue-macros/volar"],
    "vueMacros": {
      "scriptSFC": true,
    },
  },
}
```

---

---
url: /macros/setup-component.md
---
# setupComponent&#x20;

::: tip

`defineRender` cannot be disabled when using `setupComponent`.

Files in `node_modules` will be ignored by default.

:::

With `defineSetupComponent`, `<script setup>` code can be put in **pure JS/TS(X)** without [Vue Language Tools (Volar)](https://github.com/johnsoncodehk/volar) extension.

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Nuxt 3   |        :x:         |
|   Vue 2    |        :x:         |
| TypeScript |        :x:         |

See also [Vue Vine](https://vue-vine.dev/) - another style for Vue functional component.

## Basic Usage

```tsx twoslash
export const App = defineSetupComponent(() => {
  defineProps<{
    foo: string
  }>()

  defineEmits<{
    (evt: 'change'): void
  }>()

  defineOptions({
    name: 'App',
  })

  // ...
  return <div />
})
```

## Type Annotation

```ts twoslash
export const App: SetupFC = () => {
  defineProps<{
    foo: string
  }>()

  defineEmits<{
    (evt: 'change'): void
  }>()

  defineOptions({
    name: 'App',
  })
}
```

## Known Issues

* TypeScript support is not yet completed.
* The source map does not correspond properly.

---

---
url: /volar/setup-jsdoc.md
---
# setupJsdoc&#x20;

Define the component's JSDoc in the script setup block.

|   Features   |     Supported      |
| :----------: | :----------------: |
| Volar Plugin | :white\_check\_mark: |

## Basic Usage

````vue twoslash
<script setup lang="tsx">
/**
 * @example
 * ```vue
 * <Comp :foo="1" />
 * ```
 */
const Comp = () => <div />
// ---cut---
// @noErrors
import Comp from './Comp.vue'
//     ^?
</script>

<template>
  <Comp />
</template>
````

### There are two places to define

1. The first line of the script setup block.

````vue
<script setup lang="ts">
/**
 * @example
 * ```vue
 * <Comp :foo="1" />
 * ```
 */

defineProps<{
  foo: number
}>()
</script>
````

2. Above the `export default` expression.

::: tip

This feature depends on `exportRender`, and make sure `exportRender` is not disabled.

:::

````vue
<script setup lang="tsx">
defineProps<{
  foo: number
}>()

/**
 * @example
 * ```vue
 * <Comp :foo="1" />
 * ```
 */
export default <div />
</script>
````

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/setup-sfc.md
---
# setupSFC&#x20;

::: tip

If you're using `setupSFC`, then `defineRender` cannot be disabled.

:::

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|       Nuxt 3       | :white\_check\_mark: |
|       Vue 2        | :white\_check\_mark: |
| TypeScript / Volar | :white\_check\_mark: |

## Setup

::: code-group

```ts {7-14} [Vite]
// vite.config.ts
import Vue from '@vitejs/plugin-vue'
import VueMacros from 'vue-macros/vite'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue({
          include: [/\.vue$/, /\.setup\.[cm]?[jt]sx?$/],
          //                   ⬆️ setupSFC pattern need to be added
        }),
      },
    }),
  ],
})
```

```ts {6-13} [Rollup]
import Vue from 'unplugin-vue/rollup'
import VueMacros from 'vue-macros/rollup'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue({
          include: [/\.vue$/, /\.setup\.[cm]?[jt]sx?$/],
          //                   ⬆️ setupSFC pattern need to be added
        }),
      },
    }),
  ],
})
```

```[🚧 esbuild]
🚧
```

```[🚧 Webpack]
🚧
```

:::

## Basic Usage

```tsx twoslash
// Foo.setup.tsx
defineProps<{
  foo: string
}>()

defineEmits<{
  (evt: 'change'): void
}>()

export default () => (
  <div>
    <h1>Hello World</h1>
  </div>
)
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "setupSFC": true,
    },
  },
}
```

---

---
url: /features/short-bind.md
---
# shortBind&#x20;

`:value` -> `:value="value"`

Same-name shorthand for binding prop. If the attribute has the same name with the JavaScript value being bound, the syntax can be further shortened to omit the attribute value.

For Vue >= 3.4, this feature will be turned off by default.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     |        :x:         |
| Volar Plugin | :white\_check\_mark: |

## Usage

### Basic Usage

```vue twoslash
<script setup>
const value = 'foo'
</script>

<template>
  <input :value />
  <!-- => <input :foo="value" /> -->
</template>
```

### With `shortVmodel`

```vue
<template>
  <Comp ::value />
  <!-- => <Comp ::foo="foo" /> => <Comp v-model:foo="foo" /> -->
  <Comp $foo />
  <!-- => <Comp $foo="foo" /> => <Comp v-model:foo="foo" /> -->
  <Comp *foo />
  <!-- => <Comp *foo="foo" /> => <Comp v-model:foo="foo" /> -->
</template>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/short-emits.md
---
# shortEmits&#x20;

Simplify the definition of emits.

For Vue >= 3.3, this feature will be turned off by default.

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Vue 2    | :white\_check\_mark: |
| TypeScript | :white\_check\_mark: |

## Basic Usage

```vue twoslash
<script setup lang="ts">
import { defineEmits } from 'vue-macros/macros'

const emits = defineEmits<{
  // tuple
  'update:modelValue': [val: string]
  // function
  update: (val: string) => void
}>()
</script>
```

Using type `ShortEmits` or for short `SE`.

```vue twoslash
<script setup lang="ts">
const emits = defineEmits<
  SE<{
    // tuple
    'update:modelValue': [val: string]
    // function
    update: (val: string) => void
  }>
>()
</script>
```

## Difference with Official Version

* function style of declaration is not supported by official version.

---

---
url: /macros/short-vmodel.md
---
# shortVmodel&#x20;

A shorthand for `v-model`.

`v-model` -> `::` / `


  
  
  
  
  vue-macros.dev | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


   / `*`

If you have any questions about this feature, you can comment on [RFC Discussion](https://github.com/vuejs/rfcs/discussions/395).

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     |        :x:         |
| Volar Plugin | :white\_check\_mark: |

## Options

```ts
interface Options {
  /**
   * @default '
#x27; */ prefix?: '::' | '
#x27; | '*' } ``` ## Usage ### ` vue-macros.dev | Top Sites | DialtoneApp Dollar Sign (Default) ```vue <template> <input $="msg" /> <!-- => <input v-model="msg" /> --> <demo $msg="msg" /> <!-- => <input v-model:msg="msg" /> --> </template> ``` ### `::` Double Binding ```vue <template> <!-- prettier-ignore --> <input ::="msg" /> <!-- => <input v-model="msg" /> --> <demo ::msg="msg" /> <!-- => <input v-model:msg="msg" /> --> </template> ``` ### `*` Asterisk Sign ```vue <template> <input *="msg" /> <!-- => <input v-model="msg" /> --> <demo *msg="msg" /> <!-- => <input v-model:msg="msg" /> --> </template> ``` ## Volar Configuration ```jsonc {3,5-7} [tsconfig.json] { "vueCompilerOptions": { "plugins": ["vue-macros/volar"], "vueMacros": { "shortVmodel": { "prefix": "
quot;, }, }, }, } ``` ## Known Issues * Prettier will format `::=` to `:=` (e.g. `<div ::="msg" />` -> `<div :="msg" />`). The comment `<!-- prettier-ignore -->` is required if prefix is `::`. --- --- url: /volar/template-ref.md --- # templateRef&#x20; Automatically infer type for `templateRef` (from [VueUse](https://vueuse.org/core/templateRef/)) and `useTemplateRef` (Vue 3.5+). ::: warning This feature is officially supported since Volar (`vue-tsc`) v2.1.0. Vue Macros is no longer offering this feature as a plugin. ::: | Features | Supported | | :------: | :----------------: | | Volar | :white\_check\_mark: | ## Basic Usage ::: code-group ```vue [App.vue] twoslash <script setup lang="ts"> // #region comp import { defineComponent } from 'vue' export const Comp = defineComponent({ setup() { return { foo: 1 } }, }) // #endregion comp // ---cut--- import { templateRef } from '@vueuse/core' // @noErrors import { Comp } from './Comp.ts' const comp = templateRef('comp') comp.value?.foo // ^? </script> <template> <Comp ref="comp" /> </template> ``` <<< ./template-ref.md#comp{ts} \[Comp.ts] ::: ## Volar Configuration No configuration required. --- --- url: /macros.md --- # Usage List of all available macros. Please make sure `vue-macros` is set up correctly. If you haven't yet, read [Getting Started](../guide/getting-started.md) first. ## Implemented by Vue 3.3 * [defineOptions](./define-options.md) * [defineSlots](./define-slots.md) * [shortEmits](./short-emits.md) ## Stable Features * [defineModels](./define-models.md) * [defineProps](./define-props.md) * [definePropsRefs](./define-props-refs.md) * [defineRender](./define-render.md) * [shortVmodel](./short-vmodel.md) ## Experimental Features * [defineProp](./define-prop.md) * [defineEmit](./define-emit.md) * [setupComponent](./setup-component.md) * [setupSFC](./setup-sfc.md) * [chainCall](./chain-call.md) * [defineStyleX](./define-stylex.md)
-prefixed macro equivalent. These APIs include:\n\n* [`ref`](https://vuejs.org/api/reactivity-core#ref) -\u003e `$ref`\n* [`computed`](https://vuejs.org/api/reactivity-core#computed) -\u003e `$computed`\n* [`shallowRef`](https://vuejs.org/api/reactivity-advanced#shallowref) -\u003e `$shallowRef`\n* [`customRef`](https://vuejs.org/api/reactivity-advanced#customref) -\u003e `$customRef`\n* [`toRef`](https://vuejs.org/api/reactivity-utilities#toref) -\u003e `$toRef`\n\nThese macros are globally available and do not need to be imported when Reactivity Transform is enabled, but you can optionally import them from `vue-macros/macros` or `@vue-macros/reactivity-transform/macros-global` if you want to be more explicit:\n\n```js twoslash\nimport { $ref } from 'vue-macros/macros'\n// for standalone version:\n// import { $ref } from '@vue-macros/reactivity-transform/macros-global'\n\nconst count = $ref(0)\n```\n\n## Destructuring with `$()` {#destructuring-with}\n\nIt is common for a composition function to return an object of refs, and use destructuring to retrieve these refs. For this purpose, reactivity transform provides the **`$()`** macro:\n\n```js twoslash\nimport { ref } from 'vue'\nfunction useMouse() {\n return {\n x: ref(0),\n y: ref(0),\n }\n}\n// ---cut---\nconst { x, y } = $(useMouse())\n\nconsole.log(x, y)\n```\n\nCompiled output:\n\n```js twoslash\nimport { ref, toRef } from 'vue'\nfunction useMouse() {\n return {\n x: ref(0),\n y: ref(0),\n }\n}\n// ---cut---\nconst __temp = useMouse()\nconst x = toRef(__temp, 'x')\nconst y = toRef(__temp, 'y')\n\nconsole.log(x.value, y.value)\n```\n\nNote that if `x` is already a ref, `toRef(__temp, 'x')` will simply return it as-is and no additional ref will be created. If a destructured value is not a ref (e.g. a function), it will still work - the value will be wrapped in a ref so the rest of the code works as expected.\n\n`$()` destructure works on both reactive objects **and** plain objects containing refs.\n\n## Convert Existing Refs to Reactive Variables with `$()` {#convert-existing-refs-to-reactive-variables-with}\n\nIn some cases we may have wrapped functions that also return refs. However, the Vue compiler won't be able to know ahead of time that a function is going to return a ref. In such cases, the `$()` macro can also be used to convert any existing refs into reactive variables:\n\n```js twoslash\nimport { ref } from 'vue'\n\nfunction myCreateRef() {\n return ref(0)\n}\n\nconst count = $(myCreateRef())\n```\n\n## Reactive Props Destructure {#reactive-props-destructure}\n\nThere are two pain points with the current `defineProps()` usage in `\u003cscript setup\u003e`:\n\n1. Similar to `.value`, you need to always access props as `props.x` in order to retain reactivity. This means you cannot destructure `defineProps` because the resulting destructured variables are not reactive and will not update.\n\n2. When using the [type-only props declaration](https://vuejs.org/api/sfc-script-setup.html#typescript-only-features), there is no easy way to declare default values for the props. We introduced the `withDefaults()` API for this exact purpose, but it's still clunky to use.\n\nWe can address these issues by applying a compile-time transform when `defineProps` is used with destructuring, similar to what we saw earlier with `$()`:\n\n```vue twoslash\n\u003cscript setup lang=\"ts\"\u003e\nimport { watchEffect } from 'vue'\n\ninterface Props {\n msg: string\n count?: number\n foo?: string\n}\n\nconst {\n msg,\n // default value just works\n count = 1,\n // local aliasing also just works\n // here we are aliasing `props.foo` to `bar`\n foo: bar,\n} = defineProps\u003cProps\u003e()\n\nwatchEffect(() =\u003e {\n // will log whenever the props change\n console.log(msg, count, bar)\n})\n\u003c/script\u003e\n```\n\nThe above will be compiled into the following runtime declaration equivalent:\n\n```ts twoslash\nimport { defineComponent, watchEffect } from 'vue'\n\nexport default defineComponent({\n props: {\n msg: { type: String, required: true },\n count: { type: Number, default: 1 },\n foo: String,\n },\n setup(props) {\n watchEffect(() =\u003e {\n console.log(props.msg, props.count, props.foo)\n })\n },\n})\n```\n\n## Retaining Reactivity Across Function Boundaries {#retaining-reactivity-across-function-boundaries}\n\nWhile reactive variables relieve us from having to use `.value` everywhere, it creates an issue of \"reactivity loss\" when we pass reactive variables across function boundaries. This can happen in two cases:\n\n### Passing into function as argument {#passing-into-function-as-argument}\n\nGiven a function that expects a ref as an argument, e.g.:\n\n```ts twoslash\nimport { watch, type Ref } from 'vue'\n\nfunction trackChange(x: Ref\u003cnumber\u003e) {\n watch(x, (x) =\u003e {\n console.log('x changed!')\n })\n}\n\nconst count = $ref(0)\n// @errors: 2345\ntrackChange(count) // doesn't work!\n```\n\nThe above case will not work as expected because it compiles to:\n\n```ts\nconst count = ref(0)\ntrackChange(count.value)\n```\n\nHere `count.value` is passed as a number, whereas `trackChange` expects an actual ref. This can be fixed by wrapping `count` with `$()` before passing it:\n\n```diff\nlet count = $ref(0)\n- trackChange(count)\n+ trackChange($(count))\n```\n\nThe above compiles to:\n\n```js\nimport { ref } from 'vue'\n\nconst count = ref(0)\ntrackChange(count)\n```\n\nAs we can see, `$()` is a macro that serves as an **escape hint**: reactive variables inside `$()` will not get `.value` appended.\n\n### Returning inside function scope {#returning-inside-function-scope}\n\nReactivity can also be lost if reactive variables are used directly in a returned expression:\n\n```ts twoslash\nfunction useMouse() {\n const x = $ref(0)\n const y = $ref(0)\n\n // listen to mousemove...\n\n // doesn't work!\n return {\n x,\n y,\n }\n}\n```\n\nThe above return statement compiles to:\n\n```ts\nreturn {\n x: x.value,\n y: y.value,\n}\n```\n\nIn order to retain reactivity, we should be returning the actual refs, not the current value at return time.\n\nAgain, we can use `$()` to fix this. In this case, `$()` can be used directly on the returned object - any reference to reactive variables inside the `$()` call will retain the reference to their underlying refs:\n\n```ts twoslash\nfunction useMouse() {\n const x = $ref(0)\n const y = $ref(0)\n\n // listen to mousemove...\n\n // fixed\n return $({\n x,\n y,\n })\n}\n```\n\n### Using `$()` on destructured props {#using-on-destructured-props}\n\n`$()` works on destructured props since they are reactive variables as well. The compiler will convert it with `toRef` for efficiency:\n\n```vue twoslash\n\u003cscript setup lang=\"ts\"\u003e\nimport type { Ref } from 'vue'\nfunction passAsRef(count: Ref\u003cnumber\u003e) {\n return count\n}\n// ---cut---\nconst { count } = defineProps\u003c{ count: number }\u003e()\n\npassAsRef($(count))\n\u003c/script\u003e\n```\n\ncompiles to:\n\n```ts twoslash\nimport { defineComponent, toRef, type Ref } from 'vue'\nfunction passAsRef(count: Ref\u003cnumber\u003e) {\n return count\n}\n// ---cut---\nexport default defineComponent({\n props: {\n count: { type: Number, required: true },\n },\n setup(props) {\n const __props_count = toRef(props, 'count')\n passAsRef(__props_count)\n },\n})\n```\n\n## TypeScript Integration {#typescript-integration}\n\nVue provides typings for these macros (available globally) and all types will work as expected. There are no incompatibilities with standard TypeScript semantics, so the syntax will work with all existing tooling.\n\nThis also means the macros can work in any files where valid JS / TS are allowed - not just inside Vue SFCs.\n\nSince the macros are available globally, their types need to be explicitly referenced (e.g. in a `env.d.ts` file):\n\n```ts [env.d.ts]\n/// \u003creference types=\"vue-macros/macros-global\" /\u003e\n\n// or for standalone version:\n/// \u003creference types=\"@vue-macros/reactivity-transform/macros-global\" /\u003e\n```\n\nWhen explicitly importing the macros from `vue-macros/macros` or `@vue-macros/reactivity-transform/macros-global`, the type will work without declaring the globals.\n\n---\n\n---\nurl: /features/script-lang.md\n---\n# scriptLang\u0026#x20;\n\nSet the default language for `\u003cscript\u003e` block.\n\n::: tip\nConvert `\u003cscript setup\u003e` to `\u003cscript setup lang=\"ts\"\u003e`.\n:::\n\n| Features | Supported |\n| :----------: | :----------------: |\n| Vue 3 | :white\\_check\\_mark: |\n| Nuxt 3 | :white\\_check\\_mark: |\n| Vue 2 | :white\\_check\\_mark: |\n| Volar Plugin | :white\\_check\\_mark: |\n\n## Options\n\n```ts\ninterface Options {\n /**\n * @default 'ts'\n */\n defaultLang?: 'ts' | 'tsx' | 'jsx' | string\n}\n```\n\n## Usage\n\n```vue twoslash\n\u003cscript setup\u003e\ndefineProps\u003c{\n foo: string\n}\u003e()\n\u003c/script\u003e\n```\n\n## Volar Configuration\n\n```jsonc {3,5-7} [tsconfig.json]\n{\n \"vueCompilerOptions\": {\n \"plugins\": [\"vue-macros/volar\"],\n \"vueMacros\": {\n \"scriptLang\": {\n \"defaultLang\": \"ts\",\n },\n },\n },\n}\n```\n\n---\n\n---\nurl: /volar/script-sfc.md\n---\n# scriptSFC\u0026#x20;\n\nEnabled Volar support for `.ts` | `.tsx` files.\n\n| Features | Supported |\n| :----------: | :----------------: |\n| Volar Plugin | :white\\_check\\_mark: |\n\n## Basic Usage\n\n### With `jsxDirective`\n\n::: code-group\n\n```tsx [App.tsx]\nexport default ({ foo }: { foo: number }) =\u003e (\n \u003cdiv v-if={foo === 1}\u003e{foo}\u003c/div\u003e\n // ^ will be inferred as 1\n)\n```\n\n:::\n\n## Volar Configuration\n\n```jsonc {3,5} [tsconfig.json]\n{\n \"vueCompilerOptions\": {\n \"plugins\": [\"@vue-macros/volar\"],\n \"vueMacros\": {\n \"scriptSFC\": true,\n },\n },\n}\n```\n\n---\n\n---\nurl: /macros/setup-component.md\n---\n# setupComponent\u0026#x20;\n\n::: tip\n\n`defineRender` cannot be disabled when using `setupComponent`.\n\nFiles in `node_modules` will be ignored by default.\n\n:::\n\nWith `defineSetupComponent`, `\u003cscript setup\u003e` code can be put in **pure JS/TS(X)** without [Vue Language Tools (Volar)](https://github.com/johnsoncodehk/volar) extension.\n\n| Features | Supported |\n| :--------: | :----------------: |\n| Vue 3 | :white\\_check\\_mark: |\n| Nuxt 3 | :x: |\n| Vue 2 | :x: |\n| TypeScript | :x: |\n\nSee also [Vue Vine](https://vue-vine.dev/) - another style for Vue functional component.\n\n## Basic Usage\n\n```tsx twoslash\nexport const App = defineSetupComponent(() =\u003e {\n defineProps\u003c{\n foo: string\n }\u003e()\n\n defineEmits\u003c{\n (evt: 'change'): void\n }\u003e()\n\n defineOptions({\n name: 'App',\n })\n\n // ...\n return \u003cdiv /\u003e\n})\n```\n\n## Type Annotation\n\n```ts twoslash\nexport const App: SetupFC = () =\u003e {\n defineProps\u003c{\n foo: string\n }\u003e()\n\n defineEmits\u003c{\n (evt: 'change'): void\n }\u003e()\n\n defineOptions({\n name: 'App',\n })\n}\n```\n\n## Known Issues\n\n* TypeScript support is not yet completed.\n* The source map does not correspond properly.\n\n---\n\n---\nurl: /volar/setup-jsdoc.md\n---\n# setupJsdoc\u0026#x20;\n\nDefine the component's JSDoc in the script setup block.\n\n| Features | Supported |\n| :----------: | :----------------: |\n| Volar Plugin | :white\\_check\\_mark: |\n\n## Basic Usage\n\n````vue twoslash\n\u003cscript setup lang=\"tsx\"\u003e\n/**\n * @example\n * ```vue\n * \u003cComp :foo=\"1\" /\u003e\n * ```\n */\nconst Comp = () =\u003e \u003cdiv /\u003e\n// ---cut---\n// @noErrors\nimport Comp from './Comp.vue'\n// ^?\n\u003c/script\u003e\n\n\u003ctemplate\u003e\n \u003cComp /\u003e\n\u003c/template\u003e\n````\n\n### There are two places to define\n\n1. The first line of the script setup block.\n\n````vue\n\u003cscript setup lang=\"ts\"\u003e\n/**\n * @example\n * ```vue\n * \u003cComp :foo=\"1\" /\u003e\n * ```\n */\n\ndefineProps\u003c{\n foo: number\n}\u003e()\n\u003c/script\u003e\n````\n\n2. Above the `export default` expression.\n\n::: tip\n\nThis feature depends on `exportRender`, and make sure `exportRender` is not disabled.\n\n:::\n\n````vue\n\u003cscript setup lang=\"tsx\"\u003e\ndefineProps\u003c{\n foo: number\n}\u003e()\n\n/**\n * @example\n * ```vue\n * \u003cComp :foo=\"1\" /\u003e\n * ```\n */\nexport default \u003cdiv /\u003e\n\u003c/script\u003e\n````\n\n## Volar Configuration\n\n```jsonc {3} [tsconfig.json]\n{\n \"vueCompilerOptions\": {\n \"plugins\": [\"vue-macros/volar\"],\n },\n}\n```\n\n---\n\n---\nurl: /macros/setup-sfc.md\n---\n# setupSFC\u0026#x20;\n\n::: tip\n\nIf you're using `setupSFC`, then `defineRender` cannot be disabled.\n\n:::\n\n| Features | Supported |\n| :----------------: | :----------------: |\n| Vue 3 | :white\\_check\\_mark: |\n| Nuxt 3 | :white\\_check\\_mark: |\n| Vue 2 | :white\\_check\\_mark: |\n| TypeScript / Volar | :white\\_check\\_mark: |\n\n## Setup\n\n::: code-group\n\n```ts {7-14} [Vite]\n// vite.config.ts\nimport Vue from '@vitejs/plugin-vue'\nimport VueMacros from 'vue-macros/vite'\n\nexport default defineConfig({\n plugins: [\n VueMacros({\n plugins: {\n vue: Vue({\n include: [/\\.vue$/, /\\.setup\\.[cm]?[jt]sx?$/],\n // ⬆️ setupSFC pattern need to be added\n }),\n },\n }),\n ],\n})\n```\n\n```ts {6-13} [Rollup]\nimport Vue from 'unplugin-vue/rollup'\nimport VueMacros from 'vue-macros/rollup'\n\nexport default defineConfig({\n plugins: [\n VueMacros({\n plugins: {\n vue: Vue({\n include: [/\\.vue$/, /\\.setup\\.[cm]?[jt]sx?$/],\n // ⬆️ setupSFC pattern need to be added\n }),\n },\n }),\n ],\n})\n```\n\n```[🚧 esbuild]\n🚧\n```\n\n```[🚧 Webpack]\n🚧\n```\n\n:::\n\n## Basic Usage\n\n```tsx twoslash\n// Foo.setup.tsx\ndefineProps\u003c{\n foo: string\n}\u003e()\n\ndefineEmits\u003c{\n (evt: 'change'): void\n}\u003e()\n\nexport default () =\u003e (\n \u003cdiv\u003e\n \u003ch1\u003eHello World\u003c/h1\u003e\n \u003c/div\u003e\n)\n```\n\n## Volar Configuration\n\n```jsonc {3,5} [tsconfig.json]\n{\n \"vueCompilerOptions\": {\n \"plugins\": [\"vue-macros/volar\"],\n \"vueMacros\": {\n \"setupSFC\": true,\n },\n },\n}\n```\n\n---\n\n---\nurl: /features/short-bind.md\n---\n# shortBind\u0026#x20;\n\n`:value` -\u003e `:value=\"value\"`\n\nSame-name shorthand for binding prop. If the attribute has the same name with the JavaScript value being bound, the syntax can be further shortened to omit the attribute value.\n\nFor Vue \u003e= 3.4, this feature will be turned off by default.\n\n| Features | Supported |\n| :----------: | :----------------: |\n| Vue 3 | :white\\_check\\_mark: |\n| Nuxt 3 | :white\\_check\\_mark: |\n| Vue 2 | :x: |\n| Volar Plugin | :white\\_check\\_mark: |\n\n## Usage\n\n### Basic Usage\n\n```vue twoslash\n\u003cscript setup\u003e\nconst value = 'foo'\n\u003c/script\u003e\n\n\u003ctemplate\u003e\n \u003cinput :value /\u003e\n \u003c!-- =\u003e \u003cinput :foo=\"value\" /\u003e --\u003e\n\u003c/template\u003e\n```\n\n### With `shortVmodel`\n\n```vue\n\u003ctemplate\u003e\n \u003cComp ::value /\u003e\n \u003c!-- =\u003e \u003cComp ::foo=\"foo\" /\u003e =\u003e \u003cComp v-model:foo=\"foo\" /\u003e --\u003e\n \u003cComp $foo /\u003e\n \u003c!-- =\u003e \u003cComp $foo=\"foo\" /\u003e =\u003e \u003cComp v-model:foo=\"foo\" /\u003e --\u003e\n \u003cComp *foo /\u003e\n \u003c!-- =\u003e \u003cComp *foo=\"foo\" /\u003e =\u003e \u003cComp v-model:foo=\"foo\" /\u003e --\u003e\n\u003c/template\u003e\n```\n\n## Volar Configuration\n\n```jsonc {3} [tsconfig.json]\n{\n \"vueCompilerOptions\": {\n \"plugins\": [\"vue-macros/volar\"],\n },\n}\n```\n\n---\n\n---\nurl: /macros/short-emits.md\n---\n# shortEmits\u0026#x20;\n\nSimplify the definition of emits.\n\nFor Vue \u003e= 3.3, this feature will be turned off by default.\n\n| Features | Supported |\n| :--------: | :----------------: |\n| Vue 3 | :white\\_check\\_mark: |\n| Vue 2 | :white\\_check\\_mark: |\n| TypeScript | :white\\_check\\_mark: |\n\n## Basic Usage\n\n```vue twoslash\n\u003cscript setup lang=\"ts\"\u003e\nimport { defineEmits } from 'vue-macros/macros'\n\nconst emits = defineEmits\u003c{\n // tuple\n 'update:modelValue': [val: string]\n // function\n update: (val: string) =\u003e void\n}\u003e()\n\u003c/script\u003e\n```\n\nUsing type `ShortEmits` or for short `SE`.\n\n```vue twoslash\n\u003cscript setup lang=\"ts\"\u003e\nconst emits = defineEmits\u003c\n SE\u003c{\n // tuple\n 'update:modelValue': [val: string]\n // function\n update: (val: string) =\u003e void\n }\u003e\n\u003e()\n\u003c/script\u003e\n```\n\n## Difference with Official Version\n\n* function style of declaration is not supported by official version.\n\n---\n\n---\nurl: /macros/short-vmodel.md\n---\n# shortVmodel\u0026#x20;\n\nA shorthand for `v-model`.\n\n`v-model` -\u003e `::` / ` vue-macros.dev | Top Sites | DialtoneApp

Top SitesVue Macros

Machine Readiness

Stored receipt and evidence

Overall

27

Readable

90

Callable

0

Commerce

0

Payment

0

Machine Access

Inspect the site's MCP endpoint

Open MCP explorer

DialtoneApp can scan the stored discovery files for this domain, try the MCP initialize handshake, and show the raw protocol transcript.

Purchase boundary

read only

Control boundary

unknown

Payment rails

None

Payment providers

None

Payment methods

None

Payment protocols

None

Payment assets

None

Payment networks

None

Capabilities

None

Verified payment surface

No

Crypto only

No

Readable docs

llms, llms-full

Products

0

Variants

0

Priced variants

0

Currencies

0

Offers

0

Priced offers

0

Priced actions

0

Samples

Offer samples

No stored offer samples.

Samples

Action samples

No stored action samples.

Samples

Product samples

No stored product samples.

Document

robots.txt

Not stored for this site.

Document

llms.txt

Open llms.txt
# Vue Macros

> Modern Way to Writing Vue App

Explore more macros and syntax sugar to Vue.

## Table of Contents

- [&#x20;ESLint Integration&#x20;](/guide/eslint-integration.md)
- [&#x20;Nuxt Integration&#x20;](/guide/nuxt-integration.md)
- [Astro Integration&#x20;](/guide/astro-integration.md)
- [betterDefine&#x20;](/features/better-define.md)
- [booleanProp&#x20;](/features/boolean-prop.md)
- [Bundler Integration&#x20;](/guide/bundler-integration.md)
- [chainCall&#x20;](/macros/chain-call.md)
- [Configurations](/guide/configurations.md)
- [defineEmit&#x20;](/macros/define-emit.md)
- [defineGeneric&#x20;](/volar/define-generic.md)
- [defineModels&#x20;](/macros/define-models.md)
- [defineOptions&#x20;](/macros/define-options.md)
- [defineProp&#x20;](/macros/define-prop.md)
- [defineProps&#x20;](/macros/define-props.md)
- [definePropsRefs&#x20;](/macros/define-props-refs.md)
- [defineRender&#x20;](/macros/define-render.md)
- [defineSlots&#x20;](/macros/define-slots.md)
- [defineStyleX&#x20;](/macros/define-stylex.md)
- [exportExpose&#x20;](/features/export-expose.md)
- [exportProps&#x20;](/features/export-props.md)
- [exportRender&#x20;](/features/export-render.md)
- [Getting Started](/guide/getting-started.md)
- [hoistStatic&#x20;](/features/hoist-static.md)
- [jsxDirective&#x20;](/features/jsx-directive.md)
- [jsxRef&#x20;](/volar/jsx-ref.md)
- [Migration from v2 to v3](/guide/migration-v3.md)
- [namedTemplate&#x20;](/features/named-template.md)
- [Reactivity Transform&#x20;](/features/reactivity-transform.md)
- [scriptLang&#x20;](/features/script-lang.md)
- [scriptSFC&#x20;](/volar/script-sfc.md)
- [setupComponent&#x20;](/macros/setup-component.md)
- [setupJsdoc&#x20;](/volar/setup-jsdoc.md)
- [setupSFC&#x20;](/macros/setup-sfc.md)
- [shortBind&#x20;](/features/short-bind.md)
- [shortEmits&#x20;](/macros/short-emits.md)
- [shortVmodel&#x20;](/macros/short-vmodel.md)
- [templateRef&#x20;](/volar/template-ref.md)
- [Usage](/macros.md)

Document

llms-full.txt

Open llms-full.txt
---
url: /guide/eslint-integration.md
---
# &#x20;ESLint Integration&#x20;

## Installation

::: code-group

```bash [pnpm]
pnpm add -D @vue-macros/eslint-config
```

```bash [yarn]
yarn add -D @vue-macros/eslint-config
```

```bash [npm]
npm i -D @vue-macros/eslint-config
```

:::

## Configuration

### Flat Configuration

```js [eslint.config.js]
import vueMacros from '@vue-macros/eslint-config/flat'
export default [
  vueMacros,
  // ...your other configurations
]
```

### Legacy Configuration

```jsonc [.eslintrc]
{
  "extends": [
    "@vue-macros/eslint-config",
    // ...your other configurations
  ],
}
```

---

---
url: /guide/nuxt-integration.md
---
# &#x20;Nuxt Integration&#x20;

### Installation

::: code-group

```bash [npm]
npm i -D @vue-macros/nuxt
```

```bash [yarn]
yarn add -D @vue-macros/nuxt
```

```bash [pnpm]
pnpm add -D @vue-macros/nuxt
```

:::

## Configuration

```ts [nuxt.config.ts]
export default {
  modules: [
    '@vue-macros/nuxt',
    // ...
  ],
  macros: {
    // overrides config options
  },
}
```

***

:tada: Congratulations! That's all.

To learn more about the macros, please visit [All Macros](/macros/) :laughing:.

---

---
url: /guide/astro-integration.md
---
# Astro Integration&#x20;

### Installation

::: code-group

```bash [npm]
npm i -D @vue-macros/astro
```

```bash [yarn]
yarn add -D @vue-macros/astro
```

```bash [pnpm]
pnpm add -D @vue-macros/astro
```

:::

## Configuration

```ts [astro.config.mjs]
import Vue from '@astrojs/vue'
import Macros from '@vue-macros/astro'
import { defineConfig } from 'astro/config'

export default defineConfig({
  integrations: [
    Vue(),
    Macros({
      // overrides config options
    }),
  ],
})
```

## TypeScript Support & Volar Support

See the corresponding chapter on [Bundler Integration](./bundler-integration.md#typescript-support)

***

:tada: Congratulations! That's all.

To learn more about the macros, please visit [All Macros](/macros/) :laughing:.

---

---
url: /features/better-define.md
---
# betterDefine&#x20;

With enabling `betterDefine`, imported types are supported in `<script setup>` type-based-macros.

[Related issue](https://github.com/vuejs/core/issues/4294)

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Nuxt 3   | :white\_check\_mark: |
|   Vue 2    | :white\_check\_mark: |
| TypeScript | :white\_check\_mark: |

## Basic Usage

::: code-group

```vue twoslash [App.vue]
<script setup lang="ts">
// #region basic
type BaseProps = {
  title: string
}

export type { BaseProps }
// #endregion basic
// ---cut---
// @noErrors
import type { BaseProps } from './types'

interface Props extends BaseProps {
  foo: string
}
const props = defineProps<Props>()
</script>
```

<<< ./better-define.md#basic{ts} \[types.ts]

:::

## ⚠️ Limitations

### Complex types

Complex types are not supported in some key places. For example:

#### What are Complex Types?

* All utility types
  * [Built-in types](https://www.typescriptlang.org/docs/handbook/utility-types.html)
  * All types from `type-fest` package.
  * `typeof` keyword.
  * ...
* Index Signature
  ```ts
  interface Type {
    [key: string]: string
  }
  ```
* Generics will be ignored directly

#### What are Key Places?

* The names of props.

```ts
// ✅
defineProps<{
  foo: ComplexType
}>()

// ❌
defineProps<{
  [ComplexType]: string
}>()
```

* The names of emits.

```ts
interface Emits {
  (event: 'something', value: ComplexType): void // ✅
  (event: ComplexType): void // ❌
}
```

---

---
url: /features/boolean-prop.md
---
# booleanProp&#x20;

Convert `<Comp checked />` to `<Comp :checked="true" />`.

Convert `<Comp !checked />` to `<Comp :checked="false" />`.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     |        :x:         |
| Volar Plugin | :white\_check\_mark: |

## Options

```ts
interface Options {
  /**
   * @default '!'
   */
  negativePrefix?: string
}
```

## Usage

```vue twoslash
<script setup>
import type { FunctionalComponent } from 'vue'

export const Comp: FunctionalComponent<
  {
    checked: true,
    enabled: false,
  },
> = () => null
// ---cut---
// @noErrors
import Comp from './Comp.vue'
</script>

<template>
  <Comp checked !enabled />
  //             ^?
</template>
```

```vue twoslash
<script setup lang="ts">
// Comp.vue
defineProps<{
  checked: true
  enabled: false
}>()
</script>
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "booleanProp": true,
    },
  },
}
```

---

---
url: /guide/bundler-integration.md
---
# Bundler Integration&#x20;

## Installation

::: tip

Vite and Rollup are fully supported, while other bundlers have limited support.

:::

::: code-group

```bash [npm]
npm i -D vue-macros
```

```bash [yarn]
yarn add -D vue-macros
```

```bash [pnpm]
pnpm add -D vue-macros
```

:::

::: code-group

```ts [Vite]
// vite.config.ts
import Vue from '@vitejs/plugin-vue'
import VueMacros from 'vue-macros/vite'
// import VueJsx from '@vitejs/plugin-vue-jsx'
// import VueRouter from 'unplugin-vue-router/vite'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue(),
        // vueJsx: VueJsx(), // if needed
        // vueRouter: VueRouter({ // if needed
        //   extensions: ['.vue', '.setup.tsx']
        // })
      },
      // overrides plugin options
    }),
  ],
})
```

```ts [Rollup]
// rollup.config.js (Requires Rollup 3+)
import Vue from 'unplugin-vue/rollup'
import VueMacros from 'vue-macros/rollup'
// import VueRouter from 'unplugin-vue-router/rollup'

export default {
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue(),
        // vueJsx: VueJsx(), // if needed
        // vueRouter: VueRouter({ // if needed
        //   extensions: ['.vue', '.setup.tsx']
        // })
      },
      // overrides plugin options
    }),
  ],
}
```

```js [esbuild]
// esbuild.config.js
import { build } from 'esbuild'
// import VueRouter from 'unplugin-vue-router/esbuild'

build({
  plugins: [
    require('vue-macros/esbuild')({
      plugins: {
        vue: require('unplugin-vue/esbuild')(),
        // vueJsx: VueJsx(), // if needed
        // vueRouter: VueRouter({ // if needed
        //   extensions: ['.vue', '.setup.tsx']
        // })
      },
      // overrides plugin options
    }),
  ],
})
```

```js [Webpack]
// webpack.config.js (Requires Webpack 5+)
module.exports = {
  /* ... */
  plugins: [
    require('vue-macros/webpack')({
      // overrides plugin options
    }),
  ],
}
```

```js [Rspack]
// rspack.config.js
module.exports = {
  /* ... */
  plugins: [
    require('vue-macros/rspack')({
      // overrides plugin options
    }),
  ],
}
```

```js [Rsbuild]
// rsbuild.config.js
module.exports = {
  // ...
  tools: {
    rspack: {
      plugins: [
        require('vue-macros/rspack')({
          // overrides plugin options
        }),
      ],
    },
  },
}
```

```js [Vue CLI]
// vue.config.js (Requires Vue CLI 5+)
const { defineConfig } = require('@vue/cli-service')
const VueMacros = require('vue-macros/webpack')

module.exports = defineConfig({
  // ...
  // ⚠️ IMPORTANT
  parallel: false,
  configureWebpack: {
    plugins: [
      VueMacros({
        // overrides plugin options
      }),
    ],
  },
})
```

:::

## Configuration

See the [Configurations](./configurations.md) for more details.

```ts twoslash [vue-macros.config.ts]
import { defineConfig } from 'vue-macros'
export default defineConfig({
  // options
})
```

## TypeScript Support

```json {0}
// tsconfig.json
{
  "compilerOptions": {
    // ...
    "types": ["vue-macros/macros-global" /* ... */]
  }
}
```

## Volar Support

For detailed configuration, please refer to the description of the specific macro.

```jsonc [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

### Scoped Plugins

`exportExpose`, `exportProps`, and `exportRender` plugins cannot be used
at the same time unless providing a scope.

```ts twoslash [vue-macros.config.ts]
import { defineConfig } from 'vue-macros'
export default defineConfig({
  exportExpose: {
    include: ['**/export-expose/**'],
  },
  exportProps: {
    include: ['**/export-props/**'],
  },
  exportRender: {
    include: ['**/export-render/**'],
  },
})
```

***

:tada: Congratulations! You have successfully set up Vue Macros.

To learn more about the macros, please visit [All Macros](/macros/) :laughing:.

---

---
url: /macros/chain-call.md
---
# chainCall&#x20;

Extends `defineProps`, support call `withDefaults` as a chain.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    |     :question:     |
|    Vue 2     |     :question:     |
|  TypeScript  | :white\_check\_mark: |
| Volar Plugin |        :x:         |

::: tip

* `chainCall` does not support `definePropsRefs`
* To fully support TypeScript, you need to import this macro from `vue-macros/macros`.

:::

## Basic Usage

```vue
<script setup lang="ts">
const props = defineProps<{
  foo?: string
  bar?: number[]
  baz?: boolean
}>().withDefaults({
  foo: '111',
  bar: () => [1, 2, 3],
})
</script>
```

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const props = withDefaults(
  defineProps<{
    foo?: string
    bar?: number[]
    baz?: boolean
  }>(),
  {
    foo: '111',
    bar: () => [1, 2, 3],
  },
)
</script>
```

:::

Also support [props destructuring](../features/reactivity-transform.md) and JSX:

```vue
<script setup lang="ts">
const { foo } = defineProps<{ foo: string }>().withDefaults({
  foo: '111',
})
</script>
```

## TypeScript

To fully support TypeScript, you need to import this macro from `vue-macros/macros` with specific syntax.

```vue twoslash
<script setup lang="ts">
import { defineProps } from 'vue-macros/macros' with { type: 'macro' }

defineProps<{
  /* ... */
}>().withDefaults({
  /* ... */
})
// ✅ type safe
</script>
```

Works without import assertion, but tsc will report an error:

```ts twoslash
// @errors: 2339
defineProps<{
  /* ... */
}>().withDefaults({
  /* ... */
})
```

---

---
url: /guide/configurations.md
---
# Configurations

## Plugin Options

All features are enabled by default except the following.

#### Disabled by Default

* `exportExpose`
* `exportProps`
* `exportRender`
* `setupSFC`
* `booleanProp`
* `shortBind`
* `defineStyleX`

#### Disabled by Default when Vue >= 3.3

* `defineOptions`
* `defineSlots`
* `hoistStatic`
* `shortEmits`

You can re-enable them by setting the option to `true`.

```ts twoslash [vue-macros.config.(ts,js,json)]
import { defineConfig } from 'vue-macros'
export default defineConfig({
  root: '/your-project-path',

  /**
   * Vue version, 2 or 3.
   *
   * optional, detecting automatically.
   */
  version: 3,

  /** Defaults to true */
  defineModels: {
    // ...
  },

  // Enable features
  defineOptions: true,

  // Disable features
  hoistStatic: false,

  // ... more features
})
```

Refer to the macros and features page for available options.

---

---
url: /macros/define-emit.md
---
# defineEmit&#x20;

Declare single emit one by one using `defineEmit`.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     | :white\_check\_mark: |
|  TypeScript  | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

::: warning

`defineEmit` can not be used with `defineEmits` at same time

:::

## API Reference

```ts
defineEmit<T>(emitName)
defineEmit<T>(emitName, validator)

// emitName parameter can be optional,
// and will be inferred from variable name
const emitName = defineEmit<T>()
```

## Basic Usage

```vue twoslash
<script setup>
// Declare emit
const increment = defineEmit('increment')
// Infer emit name from variable name
const change = defineEmit()
// emit event
increment()
</script>
```

## With Validation

```vue twoslash
<script setup>
// Declare event with validation
const increment = defineEmit('increment', (value) => value < 20)
</script>
```

## TypeScript

```vue twoslash
<script setup lang="ts">
const increment = defineEmit('increment', (value: number) => value < 20)
const decrement = defineEmit<[value: number]>()

increment(2) // pass
// @errors: 2345
increment('2') // TS type error
</script>
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "defineEmit": true,
    },
  },
}
```

---

---
url: /volar/define-generic.md
---
# defineGeneric&#x20;

Declare single generic one by one using `DefineGeneric`.

> Especially useful for `setup-sfc`.

|   Features   |     Supported      |
| :----------: | :----------------: |
| Volar Plugin | :white\_check\_mark: |

## Basic Usage

::: code-group

```vue [App.vue] twoslash
<script setup lang="ts">
// @errors: 2322
defineOptions({
  name: 'App',
})

type T = DefineGeneric<number>

defineProps<{
  foo: T
}>()
</script>

<template>
  <App foo="1" />
</template>
```

:::

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-models.md
---
# defineModels&#x20;

Declaring and mutate `v-model` props as the same as normal variable using the `defineModels`.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

## Options

```ts
VueMacros({
  defineModels: {
    /**
     * Unified mode, only works for Vue 2
     *
     * Converts `modelValue` to `value`
     */
    unified: false,
  },
})
```

## Basic Usage

Requires [`@vueuse/core`](https://www.npmjs.com/package/@vueuse/core), install it by yourself before using.

```vue twoslash
<script setup lang="ts">
const { modelValue, count } = defineModels<{
  modelValue: string
  count: number
}>()

console.log(modelValue.value)
modelValue.value = 'newValue'
</script>
```

::: warning ❌ Object declaring is not supported.

```vue
<script setup lang="ts">
const { modelValue } = defineModels({
  modelValue: String,
})
</script>
```

:::

## With Model Options

```vue twoslash 3-6
<script setup lang="ts">
const { modelValue } = defineModels<{
  modelValue: ModelOptions<
    string,
    { defaultValue: 'something'; deep: true; passive: true }
  >
}>()
</script>
```

## With Reactivity Transform

::: warning

Assignment expression is only supported in `<script setup>` block. In other words invalid in `<template>`.

:::

[`@vueuse/core`](https://www.npmjs.com/package/@vueuse/core) is not required.

```vue twoslash {7-9}
<script setup lang="ts">
let { modelValue, count } = $defineModels<{
  modelValue: string
  count: number
}>()

console.log(modelValue)
modelValue = 'newValue'
count++
</script>
```

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const { modelValue, count } = defineProps<{
  modelValue: string
  count: number
}>()

const emit = defineEmits<{
  (evt: 'update:modelValue', value: string): void
  (evt: 'update:count', value: number): void
}>()

console.log(modelValue)
emit('update:modelValue', 'newValue')
emit('update:count', count + 1)
</script>
```

:::

## Volar Configuration

```jsonc {4,6-9} [tsconfig.json]
{
  "vueCompilerOptions": {
    "target": 3, // or 2.7 for Vue 2
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "defineModels": {
        // Only works when target is 2.7.
        "unified": true,
      },
    },
  },
}
```

---

---
url: /macros/define-options.md
---
# defineOptions&#x20;

Options API can be declared using the `defineOptions` in `<script setup>`, specifically to be able to set `name`, `props`, `emits`, and `render` inside of one function.

For Vue >= 3.3, this feature will be turned off by default.

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Nuxt 3   | :white\_check\_mark: |
|   Vue 2    | :white\_check\_mark: |
| TypeScript | :white\_check\_mark: |

## Installation Standalone Version

if you need `defineOptions` feature only, the standalone version is more appropriate for you.

### Installation

::: code-group

```bash [npm]
npm i -D unplugin-vue-define-options @vue-macros/volar
```

```bash [yarn]
yarn add -D unplugin-vue-define-options @vue-macros/volar
```

```bash [pnpm]
pnpm add -D unplugin-vue-define-options @vue-macros/volar
```

:::

::: code-group

```ts [Vite]
// vite.config.ts
import DefineOptions from 'unplugin-vue-define-options/vite'

export default defineConfig({
  plugins: [DefineOptions()],
})
```

```ts [Rollup]
// rollup.config.js
import DefineOptions from 'unplugin-vue-define-options/rollup'

export default {
  plugins: [DefineOptions()],
}
```

```js [esbuild]
// esbuild.config.js
import { build } from 'esbuild'

build({
  plugins: [require('unplugin-vue-define-options/esbuild')()],
})
```

```js [Webpack]
// webpack.config.js
module.exports = {
  /* ... */
  plugins: [require('unplugin-vue-define-options/webpack')()],
}
```

:::

### TypeScript Support

```json [tsconfig.json]
{
  "compilerOptions": {
    // ...
    "types": ["unplugin-vue-define-options/macros-global" /* ... */]
  }
}
```

## Basic Usage

```vue twoslash {3-4}
<script setup lang="ts">
defineOptions({
  name: 'Foo',
  inheritAttrs: false,
})

defineProps<{
  foo: number
}>()
</script>

<template>
  <Foo :foo="1" />
</template>
```

::: details Compiled Code

```vue twoslash
<script lang="ts">
export default {
  name: 'Foo',
  inheritAttrs: false,
}
</script>

<script setup lang="ts">
defineProps<{
  foo: number
}>()
</script>

<template>
  <Foo :foo="1" />
</template>
```

:::

## JSX in `<script setup>`

```vue twoslash {3-5}
<script setup lang="tsx">
defineOptions({
  render() {
    return <h1>Hello World</h1>
  },
})
</script>
```

::: details Compiled Code

```vue
<script lang="tsx">
export default {
  render() {
    return <h1>Hello World</h1>
  },
}
</script>
```

:::

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-prop.md
---
# defineProp&#x20;

Declare single prop one by one using `defineProp`.

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|       Nuxt 3       | :white\_check\_mark: |
|       Vue 2        | :white\_check\_mark: |
| TypeScript / Volar | :white\_check\_mark: |

::: warning

`defineProp` can not be used in the same file as type-declared `defineProps`.

:::

## Configuration

```ts
VueMacros({
  defineProp: {
    /**
     * 'kevinEdition' | 'johnsonEdition'
     * @default 'kevinEdition'
     */
    edition: 'kevinEdition',
  },
})
```

## Kevin's Edition (Default)

### API Reference

```ts
defineProp<T>(propName)
defineProp<T>(propName, options)

// propName parameter can be optional,
// and will be inferred from variable name
const propName = defineProp<T>()
```

### Basic Usage

```vue twoslash
<script setup lang="ts">
// Declare prop
const count = defineProp('count')

// Infer prop name from variable name
const value = defineProp()

// access prop value
console.log(count.value)
</script>
```

### With Options

```vue twoslash
<script setup lang="ts">
// Declare prop with options
const count = defineProp('count', {
  type: Number,
  required: true,
  default: 0,
  validator: (value: number) => value < 20,
})
</script>
```

### TypeScript

```vue twoslash
<script setup lang="ts">
// Declare prop of type number and infer prop name from variable name
const count = defineProp<number>()
count.value

// Declare prop of TS type boolean with default value
const disabled = defineProp<boolean>('disabled', { default: true })
disabled.value
</script>
```

### With Reactivity Transform

```vue twoslash
<script setup lang="ts">
const foo = $defineProp<string>('foo')

const bar = $(defineProp('bar', { default: 'bar' }))
</script>
```

## Johnson's Edition

### API Reference

```ts
// the prop name will be inferred from variable name
const propName = defineProp<T>()
const propName = defineProp<T>(defaultValue)
const propName = defineProp<T>(defaultValue, required)
const propName = defineProp<T>(defaultValue, required, rest)
```

### Basic Usage

```vue
<script setup lang="ts">
// declare prop `count` with default value `0`
const count = defineProp(0)

// declare required prop `disabled`
const disabled = defineProp(undefined, true)

// access prop value
console.log(count.value, disabled.value)
</script>
```

### With Options

```vue
<script setup lang="ts">
// Declare prop with options
const count = defineProp(0, false, {
  type: Number,
  validator: (value: number) => value < 20,
})
</script>
```

### TypeScript

```vue
<script setup lang="ts">
const count = defineProp<number>()
count.value

// Declare prop of TS type boolean with default value
const disabled = defineProp<boolean>(true)
disabled.value
</script>
```

### With Reactivity Transform

```vue
<script setup lang="ts">
const foo = $defineProp<number>()

const bar = $(defineProp(0, true))
</script>
```

### Volar Configuration

```jsonc {3,7} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "defineProp": {
        // "kevinEdition" | "johnsonEdition"
        "edition": "kevinEdition",
      },
    },
  },
}
```

---

---
url: /macros/define-props.md
---
# defineProps&#x20;

Correct types of destructured props using `$defineProps`.

See also [Vue issue](https://github.com/vuejs/core/issues/6876), [Reactivity Transform RFC](https://github.com/vuejs/rfcs/blob/reactivity-transform/active-rfcs/0000-reactivity-transform.md#defineprops-destructure-details).

|         Features          |     Supported      |
| :-----------------------: | :----------------: |
|           Vue 3           | :white\_check\_mark: |
|          Nuxt 3           | :white\_check\_mark: |
|           Vue 2           | :white\_check\_mark: |
| TypeScript / Volar Plugin | :white\_check\_mark: |

::: warning

[Reactivity Transform](../features/reactivity-transform.md) is required. You should enable it first.

:::

## Basic Usage

```vue twoslash
<script setup lang="ts">
const { foo } = $defineProps<{
  //     ^?
  foo: string[]
}>()

const fooRef = $(foo)
//     ^?
</script>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-props-refs.md
---
# definePropsRefs&#x20;

Returns refs from `defineProps` instead of a reactive object. It can be destructured without losing reactivity.

`toRefs(defineProps())` => `definePropsRefs()`

|         Features          |     Supported      |
| :-----------------------: | :----------------: |
|           Vue 3           | :white\_check\_mark: |
|          Nuxt 3           | :white\_check\_mark: |
|           Vue 2           | :white\_check\_mark: |
| TypeScript / Volar Plugin | :white\_check\_mark: |

## Basic Usage

```vue twoslash {2-3,8}
<script setup lang="ts">
// ✅ won't lose reactivity with destructuring
const { foo, bar } = definePropsRefs<{
  foo: string
  bar: number
}>()

console.log(foo.value, bar.value)
//           ^?
</script>
```

## With Default Value

```vue twoslash {2-3,8}
<script setup lang="ts">
import { withDefaults } from 'vue-macros/macros' with { type: 'macro' }

const { foo } = withDefaults(
  definePropsRefs<{
    foo?: string
  }>(),
  { foo: 'test' },
)

console.log(foo.value)
//           ^?
</script>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-render.md
---
# defineRender&#x20;

Defining render function in `<script setup>` using the `defineRender`.

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Nuxt 3   | :white\_check\_mark: |
|   Vue 2    | :white\_check\_mark: |
| TypeScript | :white\_check\_mark: |

We need more feedback on [RFC Discussion](https://github.com/vuejs/rfcs/discussions/585)!

## Basic Usage

```vue twoslash
<script setup lang="tsx">
// JSX passed directly
defineRender(
  <div>
    <span>Hello</span>
  </div>,
)

// Or using render function
defineRender(() => {
  return (
    <div>
      <h1>Hello World</h1>
    </div>
  )
})
</script>
```

---

---
url: /macros/define-slots.md
---
# defineSlots&#x20;

Declaring type of SFC slots in `<script setup>` using the `defineSlots`.

For Vue >= 3.3, this feature will be turned off by default.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |
|    Vue 2     |        :x:         |

## Basic Usage

### Short Syntax

```vue twoslash
<script setup lang="ts">
defineSlots<{
  // slot name
  title: {
    // scoped slot
    foo: 'bar' | boolean
  }
}>()
</script>
```

### Full Syntax (Official Version)

```vue twoslash
<script setup lang="ts">
defineSlots<{
  title: (scope: { text: string }) => any
}>()
</script>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-stylex.md
---
# defineStyleX&#x20;

Define and consume [StyleX](https://stylexjs.com/) styles in `<script setup>`.

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|       Nuxt 3       | :white\_check\_mark: |
| TypeScript / Volar | :white\_check\_mark: |
|       Vue 2        | :white\_check\_mark: |

## Setup

To use StyleX, you should install and configure StyleX first. The steps could change, you may want to check the [official document](https://stylexjs.com/) and the [document of StyleX bundler integrations](https://stylexjs.com/docs/learn/ecosystem/#third-party-bundler-integrations) for the latest information.

### Vite

```sh
pnpm add @stylexjs/stylex @stylex-extend/core @stylex-extend/vite -D
```

```ts [vite.config.ts] {1,13}
import { stylex } from '@stylex-extend/vite'
import Vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
import VueMacros from 'vue-macros/vite'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue(),
      },
    }),
    stylex(), // Must be placed after Vue Macros
  ],
})
```

```ts [main.ts] {2}
// import StyleX stylesheet, according to https://nonzzz.github.io/stylex-extend/integrations/vite
import 'virtual:stylex.css'
```

## Basic Usage

```vue [App.vue] twoslash
<script setup lang="ts">
const styles = defineStyleX({
  red: { color: 'red' },
})

// ...
// ---cut-start---
declare const vStylex: any
// ---cut-end---
</script>

<template>
  <p v-stylex="styles.red">Red</p>
</template>
```

:::details Compiled Code (with some simplifications)

```vue [App.vue] twoslash
<script lang="ts">
const styles = _stylex_create({
  red: { color: 'red' },
})
</script>

<script setup lang="ts">
import {
  create as _stylex_create,
  props as _stylex_props,
} from '@stylexjs/stylex'
// virtual module to provide runtime code
// ---cut-start---
// @ts-ignore
// ---cut-end---
import stylex_attrs from '/vue-macros/define-stylex/stylex-attrs'

// ...
</script>

<template>
  <p v-bind="stylex_attrs(_stylex_props(styles.red))">Red</p>
</template>
```

:::

## Conditional Styles

Optional and multiple rules are supported.

```vue [App.vue] twoslash
<script setup lang="ts">
defineProps<{ bold?: boolean }>()

const styles = defineStyleX({
  red: { color: 'red' },
  bold: { fontWeight: 'bold' },
})
// ---cut-start---
declare const vStylex: any
// ---cut-end---
</script>

<template>
  <span v-stylex="(styles.red, bold && styles.bold)">Red</span>
</template>
```

:::details Compiled Code (with some simplifications)

```vue [App.vue] twoslash
<script lang="ts">
const styles = _stylex_create({
  red: { color: 'red' },
  bold: { fontWeight: 'bold' },
})
</script>

<script setup lang="ts">
import {
  create as _stylex_create,
  props as _stylex_props,
} from '@stylexjs/stylex'
// ---cut-start---
// @ts-ignore
// ---cut-end---
import stylex_attrs from '/vue-macros/define-stylex/stylex-attrs'

defineProps<{ bold?: boolean }>()
</script>

<template>
  <span v-bind="stylex_attrs(_stylex_props(styles.red, bold && styles.bold))"
    >Red</span
  >
</template>
```

:::

---

---
url: /features/export-expose.md
---
# exportExpose&#x20;

Transform export statement as `defineExpose` params in Vue SFC `script-setup`.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    |         ?          |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

## Usage

Support these syntaxes:

* local variable/function/class
* export with alias
* export from other file
* namespace export
* rename export

### 1. local variable/function/class

```vue twoslash
<script setup lang="ts">
export const foo: string = 'foo'
export const bar = 10
export let baz: string | undefined
export var qux = fn()
// @errors: 2448 2454 2695
export const { a, b, c } = { a: 1, b: 2, c: 3 }

export function fn() {}
export class A {}
</script>
```

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const foo: string = 'foo'
const bar = 10
let baz: string | undefined
const qux = fn()
const { a, b, c } = { a: 1, b: 2, c: 3 }

function fn() {}
class A {}

defineExpose({
  foo,
  bar,
  baz,
  qux,
  a,
  b,
  c,
  fn,
  A,
})
</script>
```

:::

### 2. export with alias

```vue twoslash
<script setup lang="ts">
const foo = ''

export { foo as foo1 }
</script>
```

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const foo = 'foo'

defineExpose({
  foo1: foo,
})
</script>
```

:::

### 3. export from other file

::: code-group

```vue [App.vue] twoslash
<script setup lang="ts">
// #region export-file
const foo = 'foo'
type Foo = string

export { foo, type Foo }
// #endregion export-file
// ---cut---
// @noErrors
export { foo as bar, foo, type Foo } from './types'
</script>
```

<<< ./export-expose.md#export-file{ts} \[types.ts]

:::

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const __MACROS_expose_0 = 'foo'
const __MACROS_expose_1 = 'foo'
type Foo = string
// ---cut---
// @noErrors
import {
  foo as __MACROS_expose_0,
  foo as __MACROS_expose_1,
  type Foo,
} from './types'
defineExpose({
  foo: __MACROS_expose_0,
  bar: __MACROS_expose_1,
})
</script>
```

:::

### 4. namespace export

::: code-group

```vue [App.vue] twoslash
<script setup lang="ts">
const foo = { foo: 'foo' }
// ---cut---
// @noErrors
export * as foo from './types'
</script>
```

```ts [types.ts]
export const foo = 'foo'
```

:::

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const __MACROS_expose_0 = {
  foo: 'foo',
}
// ---cut---
// @noErrors
import * as __MACROS_expose_0 from './types'
defineExpose({
  foo: __MACROS_expose_0,
})
</script>
```

:::

### 5. rename export

```vue
<script setup lang="ts">
const foo = 1
const bar = 1

export { foo } from './types'
export * as bar from './types'
</script>
```

::: details Compiled Code

```vue
<script setup lang="ts">
import { foo as __MACROS_expose_0 } from './types'
import * as __MACROS_expose_1 from './types'

const foo = 1
const bar = 1
defineExpose({
  foo: __MACROS_expose_0,
  bar: __MACROS_expose_1,
})
</script>
```

:::

## Limitations

Currently does't support these following cases:

```ts
// 1. export all ❌
export * from '../types'

// 2. export default ❌
const a = 'a'
export default a
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "exportExpose": true,
    },
  },
}
```

---

---
url: /features/export-props.md
---
# exportProps&#x20;

[Svelte-like Declaring props](https://svelte.dev/docs#component-format-script-1-export-creates-a-component-prop) for Vue.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    |     :question:     |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

## Pre-requisite

[Reactivity Transform](./reactivity-transform.md) is required to use this feature, but it is enabled by default in Vue Macros.

`export let` will be changed to `defineModel`, which is supported in Vue 3.4+.

## Usage

Using export syntax to declare props.

```vue twoslash
<script setup lang="ts">
export let foo: string
export const bar: number = 1 // with default value
</script>
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "exportProps": true,
    },
  },
}
```

---

---
url: /features/export-render.md
---
# exportRender&#x20;

Transform the default export statement, in `<script setup>` of Vue SFC, as a component render function.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    |     :question:     |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

::: tip

This feature depends on `defineRender`, and make sure `defineRender` is not disabled.

:::

## Usage

```vue
<script setup lang="tsx">
// JSX passed directly
export default <div>ok</div>

// Or using render function
export default () => <div>ok</div>
</script>
```

## Volar Configuration

```jsonc {3,7} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "exportRender": true,
    },
  },
}
```

---

---
url: /guide/getting-started.md
---
# Getting Started

Vue Macros is a library that implements unofficial proposals and ideas for Vue,
exploring and extending its features and syntax.

We assume you are already familiar with the basic usages of Vue before you continue.

## Requirements

* Node.js `>= v20.19.0`.
* Vue `>= v2.7` or Vue `>= v3.0`.
  * Some features need Vue `>= v3.2.25`.
* VSCode extension [Vue - Official](https://marketplace.visualstudio.com/items?itemName=Vue.volar) and `vue-tsc` are v{{ version }}
  * Vue Macros will continue to adapt to the latest version as soon as possible, older versions may not be supported.

::: warning
WebStorm is not supported.
:::

## Creating a Vue Macros Project

### Installation

::: code-group

```bash [npm]
npm i -g @vue-macros/cli
```

```bash [yarn]
yarn global add @vue-macros/cli
```

```bash [pnpm]
pnpm add -g @vue-macros/cli
```

:::

This command will install [@vue-macros/cli](https://github.com/vue-macros/vue-macros-cli), the official Vue Macros scaffolding tool.

### Initialization

::: code-group

```bash [npm]
npm create vite@latest my-vue-macros -- --template vue-ts
cd my-vue-macros
vue-macros init
```

```bash [yarn]
yarn create vite my-vue-macros --template vue-ts
cd my-vue-macros
vue-macros init
```

```bash [pnpm]
pnpm create vite my-vue-macros --template vue-ts
cd my-vue-macros
vue-macros init
```

You will be presented with prompts for several optional experimental features.

:::

## Templates

* [Vite](https://github.com/vue-macros/vite)
* [Nuxt](https://github.com/vue-macros/nuxt)
* [Rsbuild](https://github.com/vue-macros/vue3-rsbuild)

🌟 More templates are welcome!

## Nuxt Integration

If you're using [Nuxt](https://nuxt.com/), read the [Nuxt Integration](./nuxt-integration.md).

## Bundler Integrations

If you're using [Vite](https://vitejs.dev/), [Rollup](https://rollupjs.org/), [esbuild](https://esbuild.github.io/), [Webpack](https://webpack.js.org/), or [Rspack](https://www.rspack.dev/), read the [Bundler Integration](./bundler-integration.md).

---

---
url: /features/hoist-static.md
---
# hoistStatic&#x20;

With enabling `hoistStatic`, constants declared in macros of `<script setup>` can be referenced.

For Vue >= 3.3, this feature will be turned off by default.

| Features |     Supported      |
| :------: | :----------------: |
|  Vue 3   | :white\_check\_mark: |
|  Nuxt 3  | :white\_check\_mark: |
|  Vue 2   | :white\_check\_mark: |

## Basic Usage

```vue twoslash
<script setup lang="ts">
const name = 'AppFoo'
defineOptions({
  name,
})
</script>
```

::: details Compiled Code

```vue
<script lang="ts">
const name = 'AppFoo'
export default {
  name,
}
</script>
```

:::

## Magic Comments

```vue
<script setup lang="ts">
// A value that's even not a constant
const name = /* hoist-static */ fn()
defineOptions({
  name,
})
</script>
```

::: details Compiled Code

```vue
<script lang="ts">
const name = fn()
export default {
  name,
}
</script>
```

:::

---

---
url: /features/jsx-directive.md
---
# jsxDirective&#x20;

Vue built-in directives for JSX.

|  Directive  |       Vue 3        |       Vue 2        |       Volar        |
| :---------: | :----------------: | :----------------: | :----------------: |
|   `v-if`    | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
| `v-else-if` | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|  `v-else`   | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|   `v-for`   | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|   `v-on`    | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|  `v-slot`   | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|  `v-html`   | :white\_check\_mark: | :white\_check\_mark: |         /          |
|  `v-once`   | :white\_check\_mark: |        :x:         |         /          |
|  `v-memo`   | :white\_check\_mark: |        :x:         |         /          |

## Options

```ts
interface Options {
  /**
   * @default 'v-'
   */
  prefix?: string
  /**
   * @default 'vue'
   */
  lib?: 'vue' | 'react' | 'preact' | 'solid' | string
}
```

## Usage

### `v-if`, `v-else-if`, `v-else`

```vue twoslash
<script setup lang="tsx">
const { foo } = defineProps<{
  foo: number
}>()

// ---cut-start---
// prettier-ignore
// ---cut-end---
export default () => (
  <>
    <div v-if={foo === 0}>{foo}</div>

    <div v-else-if={foo === 1}>{foo}</div>
    //                          ^?

    <div v-else>{foo}</div>
    //           ^?
  </>
)
</script>
```

### `v-for`

```vue twoslash
<script setup lang="tsx">
export default () => (
  <div v-for={(item, index) in 4} key={index}>
    {item}
  </div>
)
</script>
```

### `v-slot`

::: code-group

```vue [App.vue] twoslash
<script lang="tsx" setup>
// #region v-slot
import type { FunctionalComponent } from 'vue'

export const Comp: FunctionalComponent<
  {},
  {},
  {
    default: () => any
    slot: (scope: { bar: number }) => any
    slots: (scope: { baz: boolean }) => any
  }
> = () => <div />
// #endregion v-slot
// ---cut---
// @noErrors
import { Comp } from './Comp.tsx'

// ---cut-start---
// prettier-ignore
// ---cut-end---
export default () => (
  <Comp>
    default slot...
    <template v-slot:slot={{ bar }}>
      //              ^|
      {bar}
    </template>
  </Comp>
)
</script>
```

<<< ./jsx-directive.md#v-slot{tsx} \[Child.tsx]

:::

### `v-on`

::: warning

`v-on` only supports binding to an object of event / listener pairs without an argument.

:::

```tsx
<form v-on={{ submit }} />
```

## Dynamic Arguments

It is also possible to use a variable in a directive argument by wrapping it with a pair of `


  
  
  
  
  vue-macros.dev | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


  :

`v-model`

::: code-group

```vue [App.vue] twoslash
<script setup lang="tsx">
// ---cut-start---
// #region v-model
import { ref, type FunctionalComponent } from 'vue'

export const Comp: FunctionalComponent<
  {
    model: string
    models: string[]
  },
  {
    'update:model': [value: string]
    'update:models': [value: string[]]
  }
> = () => <div />
// #endregion v-model
// ---cut-end---
// @noErrors
import { Comp } from './Comp.tsx'

const name = ref('model')
const model = defineModel<string>()

export default () => (
  <Comp
    v-model:$name$={model.value}
    v-model:model={model.value}
    //       ^|
  />
)
</script>
```

<<< ./jsx-directive.md#v-model{tsx} \[Comp.tsx]

:::

`v-slot`

::: code-group

```vue [App.vue] twoslash
<script setup lang="tsx">
// ---cut-start---
// #region v-slot-dynamic
import type { FunctionalComponent } from 'vue'

export const Comp: FunctionalComponent<
  {},
  {},
  {
    default: (scope: { foo: string }) => any
    title: (scope: { bar: number }) => any
  }
> = () => <div />
// #endregion v-slot-dynamic
// ---cut-end---
// @noErrors
import { Comp } from './Comp.tsx'

const slots = defineSlots<{
  default: (scope: { foo: string }) => any
  title: (scope: { bar: number }) => any
}>()

// ---cut-start---
// prettier-ignore
// ---cut-end---
export default () => (
  <Comp>
    <template v-for={(Slot, name) in slots} v-slot:$name$={scope}>
      //                                             ^?
      <Slot {...scope} />
    </template>
  </Comp>
)
</script>
```

<<< ./jsx-directive.md#v-slot-dynamic{tsx} \[Comp.tsx]

:::

## Modifiers

Modifiers are special postfixes denoted by a `_`, which indicate that a directive should be bound in some special way.

```tsx
<form onSubmit_prevent>
  <input v-model_number={value} />
</form>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /volar/jsx-ref.md
---
# jsxRef&#x20;

Automatically infer type for `useRef`.

| Features |     Supported      |
| :------: | :----------------: |
|  Volar   | :white\_check\_mark: |

## Setup Auto Import

::: code-group

```ts [vite.config.ts]
import AutoImport from 'unplugin-auto-import/vite'

export default defineConfig({
  plugins: [
    AutoImport({
      imports: [
        {
          from: 'vue',
          imports: [['shallowRef', 'useRef']],
        },
      ],
    }),
  ],
})
```

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  imports: {
    presets: [
      {
        from: 'vue',
        imports: [['shallowRef', 'useRef']],
      },
    ],
  },
})
```

:::

## Basic Usage

::: code-group

```vue [App.vue] twoslash
<script lang="tsx">
// #region comp
import { defineComponent } from 'vue'

export const Comp = defineComponent({
  setup() {
    return { foo: 1 }
  },
})
// #endregion comp
// ---cut---
import { useRef } from 'vue-macros/runtime'
// Or import { shallowRef as useRef } from 'vue'
// @noErrors
import { Comp } from './Comp.ts'

export default defineComponent(() => {
  const comp = useRef()
  comp.value?.foo
  //           ^?

  return () => (
    <>
      <Comp ref={comp} />
    </>
  )
})
</script>
```

<<< ./jsx-ref.md#comp{ts} \[Comp.ts]

:::

## Volar Configuration

```jsonc [tsconfig.json] {3,6}
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "jsxRef": {
        "alias": ["useRef"],
      },
    },
  },
}
```

---

---
url: /guide/migration-v3.md
---
# Migration from v2 to v3

## Unified Version Management

Initially, we used [`changesets`](https://github.com/changesets/changesets) to
manage the versions of all packages in the monorepo. However, after two years of experimentation,
we decided to adopt a single-version strategy in v3,
where all sub-packages share the same version number, similar to Vue and Babel.
This decision stemmed from our observation that when a sub-package underwent a major change or minor update,
the version number of the main package did not adequately reflect these changes.

For example, when `@vue-macros/define-prop` introduced a breaking change,
how should `unplugin-vue-macros` release a new version?
Should it be a minor or a patch release? When users updated `unplugin-vue-macros`,
they couldn’t easily determine whether the update was due to changes in `@vue-macros/define-prop`.

Therefore, after Anthony proposed [Epoch Semantic Versioning](https://antfu.me/posts/epoch-semver),
we decided to adopt a more frequent major version update strategy,
with all packages sharing the same version number and maintaining a single unified changelog.

## Main Package Rename

We have renamed the main package from `unplugin-vue-macros` to **`vue-macros`**.
After the official release of v3, `unplugin-vue-macros` will be marked as deprecated.

As a result, you will need to update your `package.json` and the import statements for Vue Macros:

```diff
 // package.json
 {
   "devDependencies": {
-    "unplugin-vue-macros": "^2.14.5"
+    "vue-macros": "^3.0.0"
   }
 }
```

```diff
- import { $ref } from 'unplugin-vue-macros/macros'
+ import { $ref } from 'vue-macros/macros'

- import VueMacros from 'unplugin-vue-macros/vite'
+ import VueMacros from 'vue-macros/vite'
```

## Dropping Vue 2 Support

Vue 2 reached its end of life (EOL) at the end of 2023, so we have decided to drop support for Vue 2 in v3.
If you are still using Vue 2, we recommend continuing with v2 or
considering our [paid support plan](https://github.com/vue-macros/vue-macros/issues/373).

## Node.js Compatibility Changes

In v3, we have dropped support for Node.js versions below 20.19.
This means the minimum Node.js version requirement for v3 is `20.19.0`.
Additionally, we have removed CommonJS (CJS) outputs and now only provide ECMAScript modules (ESM).

## Dropping Webpack 4 Support

Since Webpack 4 cannot run in Node.js 18 or later environments,
we have also dropped support for Webpack 4 and Vue CLI 4.
We recommend upgrading to modern build tools like Vite or Rspack.

---

---
url: /features/named-template.md
---
# namedTemplate&#x20;

::: warning

Not actively maintained now. Try [createReusableTemplate](https://vueuse.org/core/createReusableTemplate/) instead.

:::

With enabling `namedTemplate`, `<template>` can be referenced like a variable.

Sometimes we need to reverse the order of the very simple components, and don't want to give the features of Vue template up and use JSX/TSX. Then this feature is much helpful.

If you support this feature, you can go to [the discussion](https://github.com/vuejs/core/discussions/6898) and hit like :+1: or comment.

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|      Vue 3.3       |        :x:         |
|       Nuxt 3       |        :x:         |
|       Vue 2        |        :x:         |
| TypeScript / Volar |        :x:         |

## Basic Usage

```vue {5-7,10-12,16-18}
<script setup>
const pager = 'top'
</script>

<template name="pager">
  <span>This is pager</span>
</template>

<template>
  <template v-if="pager === 'top'">
    <template is="pager" />
  </template>

  <span>Here is data table</span>

  <template v-if="pager === 'bottom'">
    <template is="pager" />
  </template>
</template>
```

## Known Usage

* TypeScript / Volar support is not yet completed.

---

---
url: /features/reactivity-transform.md
---
# Reactivity Transform&#x20;

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|       Nuxt 3       | :white\_check\_mark: |
|       Vue 2        | :white\_check\_mark: |
| TypeScript / Volar | :white\_check\_mark: |

## Installation Standalone Version

if you need Reactivity Transform feature only, the standalone version is more appropriate for you.

### Installation

::: code-group

```bash [npm]
npm i -D @vue-macros/reactivity-transform
```

```bash [yarn]
yarn add -D @vue-macros/reactivity-transform
```

```bash [pnpm]
pnpm add -D @vue-macros/reactivity-transform
```

:::

::: code-group

```ts [Vite]
// vite.config.ts
import ReactivityTransform from '@vue-macros/reactivity-transform/vite'

export default defineConfig({
  plugins: [ReactivityTransform()],
})
```

```ts [Rollup]
// rollup.config.js
import ReactivityTransform from '@vue-macros/reactivity-transform/rollup'

export default {
  plugins: [ReactivityTransform()],
}
```

```js [esbuild]
// esbuild.config.js
import { build } from 'esbuild'

build({
  plugins: [require('@vue-macros/reactivity-transform/esbuild')()],
})
```

```js [Webpack]
// webpack.config.js
module.exports = {
  /* ... */
  plugins: [require('@vue-macros/reactivity-transform/webpack')()],
}
```

:::

### TypeScript Support

```json [tsconfig.json]
{
  "compilerOptions": {
    // ...
    "types": ["@vue-macros/reactivity-transform/macros-global" /* ... */]
  }
}
```

## Refs vs. Reactive Variables {#refs-vs-reactive-variables}

Ever since the introduction of the Composition API, one of the primary unresolved questions is the use of refs vs. reactive objects. It's easy to lose reactivity when destructuring reactive objects, while it can be cumbersome to use `.value` everywhere when using refs. Also, `.value` is easy to miss if not using a type system.

Reactivity Transform is a compile-time transform that allows us to write code like this:

```vue twoslash
<script setup>
let count = $ref(0)

console.log(count)

function increment() {
  count++
}
</script>

<template>
  <button @click="increment">{{ count }}</button>
</template>
```

The `$ref()` method here is a **compile-time macro**: it is not an actual method that will be called at runtime. Instead, the Vue compiler uses it as a hint to treat the resulting `count` variable as a **reactive variable.**

Reactive variables can be accessed and re-assigned just like normal variables, but these operations are compiled into refs with `.value`. For example, the `<script>` part of the above component is compiled into:

```js{5,8} twoslash
import { ref } from 'vue'

let count = ref(0)

console.log(count.value)

function increment() {
  count.value++
}
```

Every reactivity API that returns refs will have a `


  
  
  
  
  vue-macros.dev | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


  -prefixed macro equivalent. These APIs include:

* [`ref`](https://vuejs.org/api/reactivity-core#ref) -> `$ref`
* [`computed`](https://vuejs.org/api/reactivity-core#computed) -> `$computed`
* [`shallowRef`](https://vuejs.org/api/reactivity-advanced#shallowref) -> `$shallowRef`
* [`customRef`](https://vuejs.org/api/reactivity-advanced#customref) -> `$customRef`
* [`toRef`](https://vuejs.org/api/reactivity-utilities#toref) -> `$toRef`

These macros are globally available and do not need to be imported when Reactivity Transform is enabled, but you can optionally import them from `vue-macros/macros` or `@vue-macros/reactivity-transform/macros-global` if you want to be more explicit:

```js twoslash
import { $ref } from 'vue-macros/macros'
// for standalone version:
// import { $ref } from '@vue-macros/reactivity-transform/macros-global'

const count = $ref(0)
```

## Destructuring with `$()` {#destructuring-with}

It is common for a composition function to return an object of refs, and use destructuring to retrieve these refs. For this purpose, reactivity transform provides the **`$()`** macro:

```js twoslash
import { ref } from 'vue'
function useMouse() {
  return {
    x: ref(0),
    y: ref(0),
  }
}
// ---cut---
const { x, y } = $(useMouse())

console.log(x, y)
```

Compiled output:

```js twoslash
import { ref, toRef } from 'vue'
function useMouse() {
  return {
    x: ref(0),
    y: ref(0),
  }
}
// ---cut---
const __temp = useMouse()
const x = toRef(__temp, 'x')
const y = toRef(__temp, 'y')

console.log(x.value, y.value)
```

Note that if `x` is already a ref, `toRef(__temp, 'x')` will simply return it as-is and no additional ref will be created. If a destructured value is not a ref (e.g. a function), it will still work - the value will be wrapped in a ref so the rest of the code works as expected.

`$()` destructure works on both reactive objects **and** plain objects containing refs.

## Convert Existing Refs to Reactive Variables with `$()` {#convert-existing-refs-to-reactive-variables-with}

In some cases we may have wrapped functions that also return refs. However, the Vue compiler won't be able to know ahead of time that a function is going to return a ref. In such cases, the `$()` macro can also be used to convert any existing refs into reactive variables:

```js twoslash
import { ref } from 'vue'

function myCreateRef() {
  return ref(0)
}

const count = $(myCreateRef())
```

## Reactive Props Destructure {#reactive-props-destructure}

There are two pain points with the current `defineProps()` usage in `<script setup>`:

1. Similar to `.value`, you need to always access props as `props.x` in order to retain reactivity. This means you cannot destructure `defineProps` because the resulting destructured variables are not reactive and will not update.

2. When using the [type-only props declaration](https://vuejs.org/api/sfc-script-setup.html#typescript-only-features), there is no easy way to declare default values for the props. We introduced the `withDefaults()` API for this exact purpose, but it's still clunky to use.

We can address these issues by applying a compile-time transform when `defineProps` is used with destructuring, similar to what we saw earlier with `$()`:

```vue twoslash
<script setup lang="ts">
import { watchEffect } from 'vue'

interface Props {
  msg: string
  count?: number
  foo?: string
}

const {
  msg,
  // default value just works
  count = 1,
  // local aliasing also just works
  // here we are aliasing `props.foo` to `bar`
  foo: bar,
} = defineProps<Props>()

watchEffect(() => {
  // will log whenever the props change
  console.log(msg, count, bar)
})
</script>
```

The above will be compiled into the following runtime declaration equivalent:

```ts twoslash
import { defineComponent, watchEffect } from 'vue'

export default defineComponent({
  props: {
    msg: { type: String, required: true },
    count: { type: Number, default: 1 },
    foo: String,
  },
  setup(props) {
    watchEffect(() => {
      console.log(props.msg, props.count, props.foo)
    })
  },
})
```

## Retaining Reactivity Across Function Boundaries {#retaining-reactivity-across-function-boundaries}

While reactive variables relieve us from having to use `.value` everywhere, it creates an issue of "reactivity loss" when we pass reactive variables across function boundaries. This can happen in two cases:

### Passing into function as argument {#passing-into-function-as-argument}

Given a function that expects a ref as an argument, e.g.:

```ts twoslash
import { watch, type Ref } from 'vue'

function trackChange(x: Ref<number>) {
  watch(x, (x) => {
    console.log('x changed!')
  })
}

const count = $ref(0)
// @errors: 2345
trackChange(count) // doesn't work!
```

The above case will not work as expected because it compiles to:

```ts
const count = ref(0)
trackChange(count.value)
```

Here `count.value` is passed as a number, whereas `trackChange` expects an actual ref. This can be fixed by wrapping `count` with `$()` before passing it:

```diff
let count = $ref(0)
- trackChange(count)
+ trackChange($(count))
```

The above compiles to:

```js
import { ref } from 'vue'

const count = ref(0)
trackChange(count)
```

As we can see, `$()` is a macro that serves as an **escape hint**: reactive variables inside `$()` will not get `.value` appended.

### Returning inside function scope {#returning-inside-function-scope}

Reactivity can also be lost if reactive variables are used directly in a returned expression:

```ts twoslash
function useMouse() {
  const x = $ref(0)
  const y = $ref(0)

  // listen to mousemove...

  // doesn't work!
  return {
    x,
    y,
  }
}
```

The above return statement compiles to:

```ts
return {
  x: x.value,
  y: y.value,
}
```

In order to retain reactivity, we should be returning the actual refs, not the current value at return time.

Again, we can use `$()` to fix this. In this case, `$()` can be used directly on the returned object - any reference to reactive variables inside the `$()` call will retain the reference to their underlying refs:

```ts twoslash
function useMouse() {
  const x = $ref(0)
  const y = $ref(0)

  // listen to mousemove...

  // fixed
  return $({
    x,
    y,
  })
}
```

### Using `$()` on destructured props {#using-on-destructured-props}

`$()` works on destructured props since they are reactive variables as well. The compiler will convert it with `toRef` for efficiency:

```vue twoslash
<script setup lang="ts">
import type { Ref } from 'vue'
function passAsRef(count: Ref<number>) {
  return count
}
// ---cut---
const { count } = defineProps<{ count: number }>()

passAsRef($(count))
</script>
```

compiles to:

```ts twoslash
import { defineComponent, toRef, type Ref } from 'vue'
function passAsRef(count: Ref<number>) {
  return count
}
// ---cut---
export default defineComponent({
  props: {
    count: { type: Number, required: true },
  },
  setup(props) {
    const __props_count = toRef(props, 'count')
    passAsRef(__props_count)
  },
})
```

## TypeScript Integration  {#typescript-integration}

Vue provides typings for these macros (available globally) and all types will work as expected. There are no incompatibilities with standard TypeScript semantics, so the syntax will work with all existing tooling.

This also means the macros can work in any files where valid JS / TS are allowed - not just inside Vue SFCs.

Since the macros are available globally, their types need to be explicitly referenced (e.g. in a `env.d.ts` file):

```ts [env.d.ts]
/// <reference types="vue-macros/macros-global" />

// or for standalone version:
/// <reference types="@vue-macros/reactivity-transform/macros-global" />
```

When explicitly importing the macros from `vue-macros/macros` or `@vue-macros/reactivity-transform/macros-global`, the type will work without declaring the globals.

---

---
url: /features/script-lang.md
---
# scriptLang&#x20;

Set the default language for `<script>` block.

::: tip
Convert `<script setup>` to `<script setup lang="ts">`.
:::

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

## Options

```ts
interface Options {
  /**
   * @default 'ts'
   */
  defaultLang?: 'ts' | 'tsx' | 'jsx' | string
}
```

## Usage

```vue twoslash
<script setup>
defineProps<{
  foo: string
}>()
</script>
```

## Volar Configuration

```jsonc {3,5-7} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "scriptLang": {
        "defaultLang": "ts",
      },
    },
  },
}
```

---

---
url: /volar/script-sfc.md
---
# scriptSFC&#x20;

Enabled Volar support for `.ts` | `.tsx` files.

|   Features   |     Supported      |
| :----------: | :----------------: |
| Volar Plugin | :white\_check\_mark: |

## Basic Usage

### With `jsxDirective`

::: code-group

```tsx [App.tsx]
export default ({ foo }: { foo: number }) => (
  <div v-if={foo === 1}>{foo}</div>
  //                     ^ will be inferred as 1
)
```

:::

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["@vue-macros/volar"],
    "vueMacros": {
      "scriptSFC": true,
    },
  },
}
```

---

---
url: /macros/setup-component.md
---
# setupComponent&#x20;

::: tip

`defineRender` cannot be disabled when using `setupComponent`.

Files in `node_modules` will be ignored by default.

:::

With `defineSetupComponent`, `<script setup>` code can be put in **pure JS/TS(X)** without [Vue Language Tools (Volar)](https://github.com/johnsoncodehk/volar) extension.

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Nuxt 3   |        :x:         |
|   Vue 2    |        :x:         |
| TypeScript |        :x:         |

See also [Vue Vine](https://vue-vine.dev/) - another style for Vue functional component.

## Basic Usage

```tsx twoslash
export const App = defineSetupComponent(() => {
  defineProps<{
    foo: string
  }>()

  defineEmits<{
    (evt: 'change'): void
  }>()

  defineOptions({
    name: 'App',
  })

  // ...
  return <div />
})
```

## Type Annotation

```ts twoslash
export const App: SetupFC = () => {
  defineProps<{
    foo: string
  }>()

  defineEmits<{
    (evt: 'change'): void
  }>()

  defineOptions({
    name: 'App',
  })
}
```

## Known Issues

* TypeScript support is not yet completed.
* The source map does not correspond properly.

---

---
url: /volar/setup-jsdoc.md
---
# setupJsdoc&#x20;

Define the component's JSDoc in the script setup block.

|   Features   |     Supported      |
| :----------: | :----------------: |
| Volar Plugin | :white\_check\_mark: |

## Basic Usage

````vue twoslash
<script setup lang="tsx">
/**
 * @example
 * ```vue
 * <Comp :foo="1" />
 * ```
 */
const Comp = () => <div />
// ---cut---
// @noErrors
import Comp from './Comp.vue'
//     ^?
</script>

<template>
  <Comp />
</template>
````

### There are two places to define

1. The first line of the script setup block.

````vue
<script setup lang="ts">
/**
 * @example
 * ```vue
 * <Comp :foo="1" />
 * ```
 */

defineProps<{
  foo: number
}>()
</script>
````

2. Above the `export default` expression.

::: tip

This feature depends on `exportRender`, and make sure `exportRender` is not disabled.

:::

````vue
<script setup lang="tsx">
defineProps<{
  foo: number
}>()

/**
 * @example
 * ```vue
 * <Comp :foo="1" />
 * ```
 */
export default <div />
</script>
````

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/setup-sfc.md
---
# setupSFC&#x20;

::: tip

If you're using `setupSFC`, then `defineRender` cannot be disabled.

:::

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|       Nuxt 3       | :white\_check\_mark: |
|       Vue 2        | :white\_check\_mark: |
| TypeScript / Volar | :white\_check\_mark: |

## Setup

::: code-group

```ts {7-14} [Vite]
// vite.config.ts
import Vue from '@vitejs/plugin-vue'
import VueMacros from 'vue-macros/vite'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue({
          include: [/\.vue$/, /\.setup\.[cm]?[jt]sx?$/],
          //                   ⬆️ setupSFC pattern need to be added
        }),
      },
    }),
  ],
})
```

```ts {6-13} [Rollup]
import Vue from 'unplugin-vue/rollup'
import VueMacros from 'vue-macros/rollup'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue({
          include: [/\.vue$/, /\.setup\.[cm]?[jt]sx?$/],
          //                   ⬆️ setupSFC pattern need to be added
        }),
      },
    }),
  ],
})
```

```[🚧 esbuild]
🚧
```

```[🚧 Webpack]
🚧
```

:::

## Basic Usage

```tsx twoslash
// Foo.setup.tsx
defineProps<{
  foo: string
}>()

defineEmits<{
  (evt: 'change'): void
}>()

export default () => (
  <div>
    <h1>Hello World</h1>
  </div>
)
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "setupSFC": true,
    },
  },
}
```

---

---
url: /features/short-bind.md
---
# shortBind&#x20;

`:value` -> `:value="value"`

Same-name shorthand for binding prop. If the attribute has the same name with the JavaScript value being bound, the syntax can be further shortened to omit the attribute value.

For Vue >= 3.4, this feature will be turned off by default.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     |        :x:         |
| Volar Plugin | :white\_check\_mark: |

## Usage

### Basic Usage

```vue twoslash
<script setup>
const value = 'foo'
</script>

<template>
  <input :value />
  <!-- => <input :foo="value" /> -->
</template>
```

### With `shortVmodel`

```vue
<template>
  <Comp ::value />
  <!-- => <Comp ::foo="foo" /> => <Comp v-model:foo="foo" /> -->
  <Comp $foo />
  <!-- => <Comp $foo="foo" /> => <Comp v-model:foo="foo" /> -->
  <Comp *foo />
  <!-- => <Comp *foo="foo" /> => <Comp v-model:foo="foo" /> -->
</template>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/short-emits.md
---
# shortEmits&#x20;

Simplify the definition of emits.

For Vue >= 3.3, this feature will be turned off by default.

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Vue 2    | :white\_check\_mark: |
| TypeScript | :white\_check\_mark: |

## Basic Usage

```vue twoslash
<script setup lang="ts">
import { defineEmits } from 'vue-macros/macros'

const emits = defineEmits<{
  // tuple
  'update:modelValue': [val: string]
  // function
  update: (val: string) => void
}>()
</script>
```

Using type `ShortEmits` or for short `SE`.

```vue twoslash
<script setup lang="ts">
const emits = defineEmits<
  SE<{
    // tuple
    'update:modelValue': [val: string]
    // function
    update: (val: string) => void
  }>
>()
</script>
```

## Difference with Official Version

* function style of declaration is not supported by official version.

---

---
url: /macros/short-vmodel.md
---
# shortVmodel&#x20;

A shorthand for `v-model`.

`v-model` -> `::` / `


  
  
  
  
  vue-macros.dev | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


   / `*`

If you have any questions about this feature, you can comment on [RFC Discussion](https://github.com/vuejs/rfcs/discussions/395).

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     |        :x:         |
| Volar Plugin | :white\_check\_mark: |

## Options

```ts
interface Options {
  /**
   * @default '
#x27; */ prefix?: '::' | '
#x27; | '*' } ``` ## Usage ### ` vue-macros.dev | Top Sites | DialtoneApp Dollar Sign (Default) ```vue <template> <input $="msg" /> <!-- => <input v-model="msg" /> --> <demo $msg="msg" /> <!-- => <input v-model:msg="msg" /> --> </template> ``` ### `::` Double Binding ```vue <template> <!-- prettier-ignore --> <input ::="msg" /> <!-- => <input v-model="msg" /> --> <demo ::msg="msg" /> <!-- => <input v-model:msg="msg" /> --> </template> ``` ### `*` Asterisk Sign ```vue <template> <input *="msg" /> <!-- => <input v-model="msg" /> --> <demo *msg="msg" /> <!-- => <input v-model:msg="msg" /> --> </template> ``` ## Volar Configuration ```jsonc {3,5-7} [tsconfig.json] { "vueCompilerOptions": { "plugins": ["vue-macros/volar"], "vueMacros": { "shortVmodel": { "prefix": "
quot;, }, }, }, } ``` ## Known Issues * Prettier will format `::=` to `:=` (e.g. `<div ::="msg" />` -> `<div :="msg" />`). The comment `<!-- prettier-ignore -->` is required if prefix is `::`. --- --- url: /volar/template-ref.md --- # templateRef&#x20; Automatically infer type for `templateRef` (from [VueUse](https://vueuse.org/core/templateRef/)) and `useTemplateRef` (Vue 3.5+). ::: warning This feature is officially supported since Volar (`vue-tsc`) v2.1.0. Vue Macros is no longer offering this feature as a plugin. ::: | Features | Supported | | :------: | :----------------: | | Volar | :white\_check\_mark: | ## Basic Usage ::: code-group ```vue [App.vue] twoslash <script setup lang="ts"> // #region comp import { defineComponent } from 'vue' export const Comp = defineComponent({ setup() { return { foo: 1 } }, }) // #endregion comp // ---cut--- import { templateRef } from '@vueuse/core' // @noErrors import { Comp } from './Comp.ts' const comp = templateRef('comp') comp.value?.foo // ^? </script> <template> <Comp ref="comp" /> </template> ``` <<< ./template-ref.md#comp{ts} \[Comp.ts] ::: ## Volar Configuration No configuration required. --- --- url: /macros.md --- # Usage List of all available macros. Please make sure `vue-macros` is set up correctly. If you haven't yet, read [Getting Started](../guide/getting-started.md) first. ## Implemented by Vue 3.3 * [defineOptions](./define-options.md) * [defineSlots](./define-slots.md) * [shortEmits](./short-emits.md) ## Stable Features * [defineModels](./define-models.md) * [defineProps](./define-props.md) * [definePropsRefs](./define-props-refs.md) * [defineRender](./define-render.md) * [shortVmodel](./short-vmodel.md) ## Experimental Features * [defineProp](./define-prop.md) * [defineEmit](./define-emit.md) * [setupComponent](./setup-component.md) * [setupSFC](./setup-sfc.md) * [chainCall](./chain-call.md) * [defineStyleX](./define-stylex.md)
/ `*`\n\nIf you have any questions about this feature, you can comment on [RFC Discussion](https://github.com/vuejs/rfcs/discussions/395).\n\n| Features | Supported |\n| :----------: | :----------------: |\n| Vue 3 | :white\\_check\\_mark: |\n| Nuxt 3 | :white\\_check\\_mark: |\n| Vue 2 | :x: |\n| Volar Plugin | :white\\_check\\_mark: |\n\n## Options\n\n```ts\ninterface Options {\n /**\n * @default ' \n */\n prefix?: '::' | ' | '*'\n}\n```\n\n## Usage\n\n### ` vue-macros.dev | Top Sites | DialtoneApp

Top SitesVue Macros

Machine Readiness

Stored receipt and evidence

Overall

27

Readable

90

Callable

0

Commerce

0

Payment

0

Machine Access

Inspect the site's MCP endpoint

Open MCP explorer

DialtoneApp can scan the stored discovery files for this domain, try the MCP initialize handshake, and show the raw protocol transcript.

Purchase boundary

read only

Control boundary

unknown

Payment rails

None

Payment providers

None

Payment methods

None

Payment protocols

None

Payment assets

None

Payment networks

None

Capabilities

None

Verified payment surface

No

Crypto only

No

Readable docs

llms, llms-full

Products

0

Variants

0

Priced variants

0

Currencies

0

Offers

0

Priced offers

0

Priced actions

0

Samples

Offer samples

No stored offer samples.

Samples

Action samples

No stored action samples.

Samples

Product samples

No stored product samples.

Document

robots.txt

Not stored for this site.

Document

llms.txt

Open llms.txt
# Vue Macros

> Modern Way to Writing Vue App

Explore more macros and syntax sugar to Vue.

## Table of Contents

- [&#x20;ESLint Integration&#x20;](/guide/eslint-integration.md)
- [&#x20;Nuxt Integration&#x20;](/guide/nuxt-integration.md)
- [Astro Integration&#x20;](/guide/astro-integration.md)
- [betterDefine&#x20;](/features/better-define.md)
- [booleanProp&#x20;](/features/boolean-prop.md)
- [Bundler Integration&#x20;](/guide/bundler-integration.md)
- [chainCall&#x20;](/macros/chain-call.md)
- [Configurations](/guide/configurations.md)
- [defineEmit&#x20;](/macros/define-emit.md)
- [defineGeneric&#x20;](/volar/define-generic.md)
- [defineModels&#x20;](/macros/define-models.md)
- [defineOptions&#x20;](/macros/define-options.md)
- [defineProp&#x20;](/macros/define-prop.md)
- [defineProps&#x20;](/macros/define-props.md)
- [definePropsRefs&#x20;](/macros/define-props-refs.md)
- [defineRender&#x20;](/macros/define-render.md)
- [defineSlots&#x20;](/macros/define-slots.md)
- [defineStyleX&#x20;](/macros/define-stylex.md)
- [exportExpose&#x20;](/features/export-expose.md)
- [exportProps&#x20;](/features/export-props.md)
- [exportRender&#x20;](/features/export-render.md)
- [Getting Started](/guide/getting-started.md)
- [hoistStatic&#x20;](/features/hoist-static.md)
- [jsxDirective&#x20;](/features/jsx-directive.md)
- [jsxRef&#x20;](/volar/jsx-ref.md)
- [Migration from v2 to v3](/guide/migration-v3.md)
- [namedTemplate&#x20;](/features/named-template.md)
- [Reactivity Transform&#x20;](/features/reactivity-transform.md)
- [scriptLang&#x20;](/features/script-lang.md)
- [scriptSFC&#x20;](/volar/script-sfc.md)
- [setupComponent&#x20;](/macros/setup-component.md)
- [setupJsdoc&#x20;](/volar/setup-jsdoc.md)
- [setupSFC&#x20;](/macros/setup-sfc.md)
- [shortBind&#x20;](/features/short-bind.md)
- [shortEmits&#x20;](/macros/short-emits.md)
- [shortVmodel&#x20;](/macros/short-vmodel.md)
- [templateRef&#x20;](/volar/template-ref.md)
- [Usage](/macros.md)

Document

llms-full.txt

Open llms-full.txt
---
url: /guide/eslint-integration.md
---
# &#x20;ESLint Integration&#x20;

## Installation

::: code-group

```bash [pnpm]
pnpm add -D @vue-macros/eslint-config
```

```bash [yarn]
yarn add -D @vue-macros/eslint-config
```

```bash [npm]
npm i -D @vue-macros/eslint-config
```

:::

## Configuration

### Flat Configuration

```js [eslint.config.js]
import vueMacros from '@vue-macros/eslint-config/flat'
export default [
  vueMacros,
  // ...your other configurations
]
```

### Legacy Configuration

```jsonc [.eslintrc]
{
  "extends": [
    "@vue-macros/eslint-config",
    // ...your other configurations
  ],
}
```

---

---
url: /guide/nuxt-integration.md
---
# &#x20;Nuxt Integration&#x20;

### Installation

::: code-group

```bash [npm]
npm i -D @vue-macros/nuxt
```

```bash [yarn]
yarn add -D @vue-macros/nuxt
```

```bash [pnpm]
pnpm add -D @vue-macros/nuxt
```

:::

## Configuration

```ts [nuxt.config.ts]
export default {
  modules: [
    '@vue-macros/nuxt',
    // ...
  ],
  macros: {
    // overrides config options
  },
}
```

***

:tada: Congratulations! That's all.

To learn more about the macros, please visit [All Macros](/macros/) :laughing:.

---

---
url: /guide/astro-integration.md
---
# Astro Integration&#x20;

### Installation

::: code-group

```bash [npm]
npm i -D @vue-macros/astro
```

```bash [yarn]
yarn add -D @vue-macros/astro
```

```bash [pnpm]
pnpm add -D @vue-macros/astro
```

:::

## Configuration

```ts [astro.config.mjs]
import Vue from '@astrojs/vue'
import Macros from '@vue-macros/astro'
import { defineConfig } from 'astro/config'

export default defineConfig({
  integrations: [
    Vue(),
    Macros({
      // overrides config options
    }),
  ],
})
```

## TypeScript Support & Volar Support

See the corresponding chapter on [Bundler Integration](./bundler-integration.md#typescript-support)

***

:tada: Congratulations! That's all.

To learn more about the macros, please visit [All Macros](/macros/) :laughing:.

---

---
url: /features/better-define.md
---
# betterDefine&#x20;

With enabling `betterDefine`, imported types are supported in `<script setup>` type-based-macros.

[Related issue](https://github.com/vuejs/core/issues/4294)

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Nuxt 3   | :white\_check\_mark: |
|   Vue 2    | :white\_check\_mark: |
| TypeScript | :white\_check\_mark: |

## Basic Usage

::: code-group

```vue twoslash [App.vue]
<script setup lang="ts">
// #region basic
type BaseProps = {
  title: string
}

export type { BaseProps }
// #endregion basic
// ---cut---
// @noErrors
import type { BaseProps } from './types'

interface Props extends BaseProps {
  foo: string
}
const props = defineProps<Props>()
</script>
```

<<< ./better-define.md#basic{ts} \[types.ts]

:::

## ⚠️ Limitations

### Complex types

Complex types are not supported in some key places. For example:

#### What are Complex Types?

* All utility types
  * [Built-in types](https://www.typescriptlang.org/docs/handbook/utility-types.html)
  * All types from `type-fest` package.
  * `typeof` keyword.
  * ...
* Index Signature
  ```ts
  interface Type {
    [key: string]: string
  }
  ```
* Generics will be ignored directly

#### What are Key Places?

* The names of props.

```ts
// ✅
defineProps<{
  foo: ComplexType
}>()

// ❌
defineProps<{
  [ComplexType]: string
}>()
```

* The names of emits.

```ts
interface Emits {
  (event: 'something', value: ComplexType): void // ✅
  (event: ComplexType): void // ❌
}
```

---

---
url: /features/boolean-prop.md
---
# booleanProp&#x20;

Convert `<Comp checked />` to `<Comp :checked="true" />`.

Convert `<Comp !checked />` to `<Comp :checked="false" />`.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     |        :x:         |
| Volar Plugin | :white\_check\_mark: |

## Options

```ts
interface Options {
  /**
   * @default '!'
   */
  negativePrefix?: string
}
```

## Usage

```vue twoslash
<script setup>
import type { FunctionalComponent } from 'vue'

export const Comp: FunctionalComponent<
  {
    checked: true,
    enabled: false,
  },
> = () => null
// ---cut---
// @noErrors
import Comp from './Comp.vue'
</script>

<template>
  <Comp checked !enabled />
  //             ^?
</template>
```

```vue twoslash
<script setup lang="ts">
// Comp.vue
defineProps<{
  checked: true
  enabled: false
}>()
</script>
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "booleanProp": true,
    },
  },
}
```

---

---
url: /guide/bundler-integration.md
---
# Bundler Integration&#x20;

## Installation

::: tip

Vite and Rollup are fully supported, while other bundlers have limited support.

:::

::: code-group

```bash [npm]
npm i -D vue-macros
```

```bash [yarn]
yarn add -D vue-macros
```

```bash [pnpm]
pnpm add -D vue-macros
```

:::

::: code-group

```ts [Vite]
// vite.config.ts
import Vue from '@vitejs/plugin-vue'
import VueMacros from 'vue-macros/vite'
// import VueJsx from '@vitejs/plugin-vue-jsx'
// import VueRouter from 'unplugin-vue-router/vite'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue(),
        // vueJsx: VueJsx(), // if needed
        // vueRouter: VueRouter({ // if needed
        //   extensions: ['.vue', '.setup.tsx']
        // })
      },
      // overrides plugin options
    }),
  ],
})
```

```ts [Rollup]
// rollup.config.js (Requires Rollup 3+)
import Vue from 'unplugin-vue/rollup'
import VueMacros from 'vue-macros/rollup'
// import VueRouter from 'unplugin-vue-router/rollup'

export default {
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue(),
        // vueJsx: VueJsx(), // if needed
        // vueRouter: VueRouter({ // if needed
        //   extensions: ['.vue', '.setup.tsx']
        // })
      },
      // overrides plugin options
    }),
  ],
}
```

```js [esbuild]
// esbuild.config.js
import { build } from 'esbuild'
// import VueRouter from 'unplugin-vue-router/esbuild'

build({
  plugins: [
    require('vue-macros/esbuild')({
      plugins: {
        vue: require('unplugin-vue/esbuild')(),
        // vueJsx: VueJsx(), // if needed
        // vueRouter: VueRouter({ // if needed
        //   extensions: ['.vue', '.setup.tsx']
        // })
      },
      // overrides plugin options
    }),
  ],
})
```

```js [Webpack]
// webpack.config.js (Requires Webpack 5+)
module.exports = {
  /* ... */
  plugins: [
    require('vue-macros/webpack')({
      // overrides plugin options
    }),
  ],
}
```

```js [Rspack]
// rspack.config.js
module.exports = {
  /* ... */
  plugins: [
    require('vue-macros/rspack')({
      // overrides plugin options
    }),
  ],
}
```

```js [Rsbuild]
// rsbuild.config.js
module.exports = {
  // ...
  tools: {
    rspack: {
      plugins: [
        require('vue-macros/rspack')({
          // overrides plugin options
        }),
      ],
    },
  },
}
```

```js [Vue CLI]
// vue.config.js (Requires Vue CLI 5+)
const { defineConfig } = require('@vue/cli-service')
const VueMacros = require('vue-macros/webpack')

module.exports = defineConfig({
  // ...
  // ⚠️ IMPORTANT
  parallel: false,
  configureWebpack: {
    plugins: [
      VueMacros({
        // overrides plugin options
      }),
    ],
  },
})
```

:::

## Configuration

See the [Configurations](./configurations.md) for more details.

```ts twoslash [vue-macros.config.ts]
import { defineConfig } from 'vue-macros'
export default defineConfig({
  // options
})
```

## TypeScript Support

```json {0}
// tsconfig.json
{
  "compilerOptions": {
    // ...
    "types": ["vue-macros/macros-global" /* ... */]
  }
}
```

## Volar Support

For detailed configuration, please refer to the description of the specific macro.

```jsonc [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

### Scoped Plugins

`exportExpose`, `exportProps`, and `exportRender` plugins cannot be used
at the same time unless providing a scope.

```ts twoslash [vue-macros.config.ts]
import { defineConfig } from 'vue-macros'
export default defineConfig({
  exportExpose: {
    include: ['**/export-expose/**'],
  },
  exportProps: {
    include: ['**/export-props/**'],
  },
  exportRender: {
    include: ['**/export-render/**'],
  },
})
```

***

:tada: Congratulations! You have successfully set up Vue Macros.

To learn more about the macros, please visit [All Macros](/macros/) :laughing:.

---

---
url: /macros/chain-call.md
---
# chainCall&#x20;

Extends `defineProps`, support call `withDefaults` as a chain.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    |     :question:     |
|    Vue 2     |     :question:     |
|  TypeScript  | :white\_check\_mark: |
| Volar Plugin |        :x:         |

::: tip

* `chainCall` does not support `definePropsRefs`
* To fully support TypeScript, you need to import this macro from `vue-macros/macros`.

:::

## Basic Usage

```vue
<script setup lang="ts">
const props = defineProps<{
  foo?: string
  bar?: number[]
  baz?: boolean
}>().withDefaults({
  foo: '111',
  bar: () => [1, 2, 3],
})
</script>
```

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const props = withDefaults(
  defineProps<{
    foo?: string
    bar?: number[]
    baz?: boolean
  }>(),
  {
    foo: '111',
    bar: () => [1, 2, 3],
  },
)
</script>
```

:::

Also support [props destructuring](../features/reactivity-transform.md) and JSX:

```vue
<script setup lang="ts">
const { foo } = defineProps<{ foo: string }>().withDefaults({
  foo: '111',
})
</script>
```

## TypeScript

To fully support TypeScript, you need to import this macro from `vue-macros/macros` with specific syntax.

```vue twoslash
<script setup lang="ts">
import { defineProps } from 'vue-macros/macros' with { type: 'macro' }

defineProps<{
  /* ... */
}>().withDefaults({
  /* ... */
})
// ✅ type safe
</script>
```

Works without import assertion, but tsc will report an error:

```ts twoslash
// @errors: 2339
defineProps<{
  /* ... */
}>().withDefaults({
  /* ... */
})
```

---

---
url: /guide/configurations.md
---
# Configurations

## Plugin Options

All features are enabled by default except the following.

#### Disabled by Default

* `exportExpose`
* `exportProps`
* `exportRender`
* `setupSFC`
* `booleanProp`
* `shortBind`
* `defineStyleX`

#### Disabled by Default when Vue >= 3.3

* `defineOptions`
* `defineSlots`
* `hoistStatic`
* `shortEmits`

You can re-enable them by setting the option to `true`.

```ts twoslash [vue-macros.config.(ts,js,json)]
import { defineConfig } from 'vue-macros'
export default defineConfig({
  root: '/your-project-path',

  /**
   * Vue version, 2 or 3.
   *
   * optional, detecting automatically.
   */
  version: 3,

  /** Defaults to true */
  defineModels: {
    // ...
  },

  // Enable features
  defineOptions: true,

  // Disable features
  hoistStatic: false,

  // ... more features
})
```

Refer to the macros and features page for available options.

---

---
url: /macros/define-emit.md
---
# defineEmit&#x20;

Declare single emit one by one using `defineEmit`.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     | :white\_check\_mark: |
|  TypeScript  | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

::: warning

`defineEmit` can not be used with `defineEmits` at same time

:::

## API Reference

```ts
defineEmit<T>(emitName)
defineEmit<T>(emitName, validator)

// emitName parameter can be optional,
// and will be inferred from variable name
const emitName = defineEmit<T>()
```

## Basic Usage

```vue twoslash
<script setup>
// Declare emit
const increment = defineEmit('increment')
// Infer emit name from variable name
const change = defineEmit()
// emit event
increment()
</script>
```

## With Validation

```vue twoslash
<script setup>
// Declare event with validation
const increment = defineEmit('increment', (value) => value < 20)
</script>
```

## TypeScript

```vue twoslash
<script setup lang="ts">
const increment = defineEmit('increment', (value: number) => value < 20)
const decrement = defineEmit<[value: number]>()

increment(2) // pass
// @errors: 2345
increment('2') // TS type error
</script>
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "defineEmit": true,
    },
  },
}
```

---

---
url: /volar/define-generic.md
---
# defineGeneric&#x20;

Declare single generic one by one using `DefineGeneric`.

> Especially useful for `setup-sfc`.

|   Features   |     Supported      |
| :----------: | :----------------: |
| Volar Plugin | :white\_check\_mark: |

## Basic Usage

::: code-group

```vue [App.vue] twoslash
<script setup lang="ts">
// @errors: 2322
defineOptions({
  name: 'App',
})

type T = DefineGeneric<number>

defineProps<{
  foo: T
}>()
</script>

<template>
  <App foo="1" />
</template>
```

:::

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-models.md
---
# defineModels&#x20;

Declaring and mutate `v-model` props as the same as normal variable using the `defineModels`.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

## Options

```ts
VueMacros({
  defineModels: {
    /**
     * Unified mode, only works for Vue 2
     *
     * Converts `modelValue` to `value`
     */
    unified: false,
  },
})
```

## Basic Usage

Requires [`@vueuse/core`](https://www.npmjs.com/package/@vueuse/core), install it by yourself before using.

```vue twoslash
<script setup lang="ts">
const { modelValue, count } = defineModels<{
  modelValue: string
  count: number
}>()

console.log(modelValue.value)
modelValue.value = 'newValue'
</script>
```

::: warning ❌ Object declaring is not supported.

```vue
<script setup lang="ts">
const { modelValue } = defineModels({
  modelValue: String,
})
</script>
```

:::

## With Model Options

```vue twoslash 3-6
<script setup lang="ts">
const { modelValue } = defineModels<{
  modelValue: ModelOptions<
    string,
    { defaultValue: 'something'; deep: true; passive: true }
  >
}>()
</script>
```

## With Reactivity Transform

::: warning

Assignment expression is only supported in `<script setup>` block. In other words invalid in `<template>`.

:::

[`@vueuse/core`](https://www.npmjs.com/package/@vueuse/core) is not required.

```vue twoslash {7-9}
<script setup lang="ts">
let { modelValue, count } = $defineModels<{
  modelValue: string
  count: number
}>()

console.log(modelValue)
modelValue = 'newValue'
count++
</script>
```

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const { modelValue, count } = defineProps<{
  modelValue: string
  count: number
}>()

const emit = defineEmits<{
  (evt: 'update:modelValue', value: string): void
  (evt: 'update:count', value: number): void
}>()

console.log(modelValue)
emit('update:modelValue', 'newValue')
emit('update:count', count + 1)
</script>
```

:::

## Volar Configuration

```jsonc {4,6-9} [tsconfig.json]
{
  "vueCompilerOptions": {
    "target": 3, // or 2.7 for Vue 2
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "defineModels": {
        // Only works when target is 2.7.
        "unified": true,
      },
    },
  },
}
```

---

---
url: /macros/define-options.md
---
# defineOptions&#x20;

Options API can be declared using the `defineOptions` in `<script setup>`, specifically to be able to set `name`, `props`, `emits`, and `render` inside of one function.

For Vue >= 3.3, this feature will be turned off by default.

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Nuxt 3   | :white\_check\_mark: |
|   Vue 2    | :white\_check\_mark: |
| TypeScript | :white\_check\_mark: |

## Installation Standalone Version

if you need `defineOptions` feature only, the standalone version is more appropriate for you.

### Installation

::: code-group

```bash [npm]
npm i -D unplugin-vue-define-options @vue-macros/volar
```

```bash [yarn]
yarn add -D unplugin-vue-define-options @vue-macros/volar
```

```bash [pnpm]
pnpm add -D unplugin-vue-define-options @vue-macros/volar
```

:::

::: code-group

```ts [Vite]
// vite.config.ts
import DefineOptions from 'unplugin-vue-define-options/vite'

export default defineConfig({
  plugins: [DefineOptions()],
})
```

```ts [Rollup]
// rollup.config.js
import DefineOptions from 'unplugin-vue-define-options/rollup'

export default {
  plugins: [DefineOptions()],
}
```

```js [esbuild]
// esbuild.config.js
import { build } from 'esbuild'

build({
  plugins: [require('unplugin-vue-define-options/esbuild')()],
})
```

```js [Webpack]
// webpack.config.js
module.exports = {
  /* ... */
  plugins: [require('unplugin-vue-define-options/webpack')()],
}
```

:::

### TypeScript Support

```json [tsconfig.json]
{
  "compilerOptions": {
    // ...
    "types": ["unplugin-vue-define-options/macros-global" /* ... */]
  }
}
```

## Basic Usage

```vue twoslash {3-4}
<script setup lang="ts">
defineOptions({
  name: 'Foo',
  inheritAttrs: false,
})

defineProps<{
  foo: number
}>()
</script>

<template>
  <Foo :foo="1" />
</template>
```

::: details Compiled Code

```vue twoslash
<script lang="ts">
export default {
  name: 'Foo',
  inheritAttrs: false,
}
</script>

<script setup lang="ts">
defineProps<{
  foo: number
}>()
</script>

<template>
  <Foo :foo="1" />
</template>
```

:::

## JSX in `<script setup>`

```vue twoslash {3-5}
<script setup lang="tsx">
defineOptions({
  render() {
    return <h1>Hello World</h1>
  },
})
</script>
```

::: details Compiled Code

```vue
<script lang="tsx">
export default {
  render() {
    return <h1>Hello World</h1>
  },
}
</script>
```

:::

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-prop.md
---
# defineProp&#x20;

Declare single prop one by one using `defineProp`.

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|       Nuxt 3       | :white\_check\_mark: |
|       Vue 2        | :white\_check\_mark: |
| TypeScript / Volar | :white\_check\_mark: |

::: warning

`defineProp` can not be used in the same file as type-declared `defineProps`.

:::

## Configuration

```ts
VueMacros({
  defineProp: {
    /**
     * 'kevinEdition' | 'johnsonEdition'
     * @default 'kevinEdition'
     */
    edition: 'kevinEdition',
  },
})
```

## Kevin's Edition (Default)

### API Reference

```ts
defineProp<T>(propName)
defineProp<T>(propName, options)

// propName parameter can be optional,
// and will be inferred from variable name
const propName = defineProp<T>()
```

### Basic Usage

```vue twoslash
<script setup lang="ts">
// Declare prop
const count = defineProp('count')

// Infer prop name from variable name
const value = defineProp()

// access prop value
console.log(count.value)
</script>
```

### With Options

```vue twoslash
<script setup lang="ts">
// Declare prop with options
const count = defineProp('count', {
  type: Number,
  required: true,
  default: 0,
  validator: (value: number) => value < 20,
})
</script>
```

### TypeScript

```vue twoslash
<script setup lang="ts">
// Declare prop of type number and infer prop name from variable name
const count = defineProp<number>()
count.value

// Declare prop of TS type boolean with default value
const disabled = defineProp<boolean>('disabled', { default: true })
disabled.value
</script>
```

### With Reactivity Transform

```vue twoslash
<script setup lang="ts">
const foo = $defineProp<string>('foo')

const bar = $(defineProp('bar', { default: 'bar' }))
</script>
```

## Johnson's Edition

### API Reference

```ts
// the prop name will be inferred from variable name
const propName = defineProp<T>()
const propName = defineProp<T>(defaultValue)
const propName = defineProp<T>(defaultValue, required)
const propName = defineProp<T>(defaultValue, required, rest)
```

### Basic Usage

```vue
<script setup lang="ts">
// declare prop `count` with default value `0`
const count = defineProp(0)

// declare required prop `disabled`
const disabled = defineProp(undefined, true)

// access prop value
console.log(count.value, disabled.value)
</script>
```

### With Options

```vue
<script setup lang="ts">
// Declare prop with options
const count = defineProp(0, false, {
  type: Number,
  validator: (value: number) => value < 20,
})
</script>
```

### TypeScript

```vue
<script setup lang="ts">
const count = defineProp<number>()
count.value

// Declare prop of TS type boolean with default value
const disabled = defineProp<boolean>(true)
disabled.value
</script>
```

### With Reactivity Transform

```vue
<script setup lang="ts">
const foo = $defineProp<number>()

const bar = $(defineProp(0, true))
</script>
```

### Volar Configuration

```jsonc {3,7} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "defineProp": {
        // "kevinEdition" | "johnsonEdition"
        "edition": "kevinEdition",
      },
    },
  },
}
```

---

---
url: /macros/define-props.md
---
# defineProps&#x20;

Correct types of destructured props using `$defineProps`.

See also [Vue issue](https://github.com/vuejs/core/issues/6876), [Reactivity Transform RFC](https://github.com/vuejs/rfcs/blob/reactivity-transform/active-rfcs/0000-reactivity-transform.md#defineprops-destructure-details).

|         Features          |     Supported      |
| :-----------------------: | :----------------: |
|           Vue 3           | :white\_check\_mark: |
|          Nuxt 3           | :white\_check\_mark: |
|           Vue 2           | :white\_check\_mark: |
| TypeScript / Volar Plugin | :white\_check\_mark: |

::: warning

[Reactivity Transform](../features/reactivity-transform.md) is required. You should enable it first.

:::

## Basic Usage

```vue twoslash
<script setup lang="ts">
const { foo } = $defineProps<{
  //     ^?
  foo: string[]
}>()

const fooRef = $(foo)
//     ^?
</script>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-props-refs.md
---
# definePropsRefs&#x20;

Returns refs from `defineProps` instead of a reactive object. It can be destructured without losing reactivity.

`toRefs(defineProps())` => `definePropsRefs()`

|         Features          |     Supported      |
| :-----------------------: | :----------------: |
|           Vue 3           | :white\_check\_mark: |
|          Nuxt 3           | :white\_check\_mark: |
|           Vue 2           | :white\_check\_mark: |
| TypeScript / Volar Plugin | :white\_check\_mark: |

## Basic Usage

```vue twoslash {2-3,8}
<script setup lang="ts">
// ✅ won't lose reactivity with destructuring
const { foo, bar } = definePropsRefs<{
  foo: string
  bar: number
}>()

console.log(foo.value, bar.value)
//           ^?
</script>
```

## With Default Value

```vue twoslash {2-3,8}
<script setup lang="ts">
import { withDefaults } from 'vue-macros/macros' with { type: 'macro' }

const { foo } = withDefaults(
  definePropsRefs<{
    foo?: string
  }>(),
  { foo: 'test' },
)

console.log(foo.value)
//           ^?
</script>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-render.md
---
# defineRender&#x20;

Defining render function in `<script setup>` using the `defineRender`.

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Nuxt 3   | :white\_check\_mark: |
|   Vue 2    | :white\_check\_mark: |
| TypeScript | :white\_check\_mark: |

We need more feedback on [RFC Discussion](https://github.com/vuejs/rfcs/discussions/585)!

## Basic Usage

```vue twoslash
<script setup lang="tsx">
// JSX passed directly
defineRender(
  <div>
    <span>Hello</span>
  </div>,
)

// Or using render function
defineRender(() => {
  return (
    <div>
      <h1>Hello World</h1>
    </div>
  )
})
</script>
```

---

---
url: /macros/define-slots.md
---
# defineSlots&#x20;

Declaring type of SFC slots in `<script setup>` using the `defineSlots`.

For Vue >= 3.3, this feature will be turned off by default.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |
|    Vue 2     |        :x:         |

## Basic Usage

### Short Syntax

```vue twoslash
<script setup lang="ts">
defineSlots<{
  // slot name
  title: {
    // scoped slot
    foo: 'bar' | boolean
  }
}>()
</script>
```

### Full Syntax (Official Version)

```vue twoslash
<script setup lang="ts">
defineSlots<{
  title: (scope: { text: string }) => any
}>()
</script>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/define-stylex.md
---
# defineStyleX&#x20;

Define and consume [StyleX](https://stylexjs.com/) styles in `<script setup>`.

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|       Nuxt 3       | :white\_check\_mark: |
| TypeScript / Volar | :white\_check\_mark: |
|       Vue 2        | :white\_check\_mark: |

## Setup

To use StyleX, you should install and configure StyleX first. The steps could change, you may want to check the [official document](https://stylexjs.com/) and the [document of StyleX bundler integrations](https://stylexjs.com/docs/learn/ecosystem/#third-party-bundler-integrations) for the latest information.

### Vite

```sh
pnpm add @stylexjs/stylex @stylex-extend/core @stylex-extend/vite -D
```

```ts [vite.config.ts] {1,13}
import { stylex } from '@stylex-extend/vite'
import Vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
import VueMacros from 'vue-macros/vite'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue(),
      },
    }),
    stylex(), // Must be placed after Vue Macros
  ],
})
```

```ts [main.ts] {2}
// import StyleX stylesheet, according to https://nonzzz.github.io/stylex-extend/integrations/vite
import 'virtual:stylex.css'
```

## Basic Usage

```vue [App.vue] twoslash
<script setup lang="ts">
const styles = defineStyleX({
  red: { color: 'red' },
})

// ...
// ---cut-start---
declare const vStylex: any
// ---cut-end---
</script>

<template>
  <p v-stylex="styles.red">Red</p>
</template>
```

:::details Compiled Code (with some simplifications)

```vue [App.vue] twoslash
<script lang="ts">
const styles = _stylex_create({
  red: { color: 'red' },
})
</script>

<script setup lang="ts">
import {
  create as _stylex_create,
  props as _stylex_props,
} from '@stylexjs/stylex'
// virtual module to provide runtime code
// ---cut-start---
// @ts-ignore
// ---cut-end---
import stylex_attrs from '/vue-macros/define-stylex/stylex-attrs'

// ...
</script>

<template>
  <p v-bind="stylex_attrs(_stylex_props(styles.red))">Red</p>
</template>
```

:::

## Conditional Styles

Optional and multiple rules are supported.

```vue [App.vue] twoslash
<script setup lang="ts">
defineProps<{ bold?: boolean }>()

const styles = defineStyleX({
  red: { color: 'red' },
  bold: { fontWeight: 'bold' },
})
// ---cut-start---
declare const vStylex: any
// ---cut-end---
</script>

<template>
  <span v-stylex="(styles.red, bold && styles.bold)">Red</span>
</template>
```

:::details Compiled Code (with some simplifications)

```vue [App.vue] twoslash
<script lang="ts">
const styles = _stylex_create({
  red: { color: 'red' },
  bold: { fontWeight: 'bold' },
})
</script>

<script setup lang="ts">
import {
  create as _stylex_create,
  props as _stylex_props,
} from '@stylexjs/stylex'
// ---cut-start---
// @ts-ignore
// ---cut-end---
import stylex_attrs from '/vue-macros/define-stylex/stylex-attrs'

defineProps<{ bold?: boolean }>()
</script>

<template>
  <span v-bind="stylex_attrs(_stylex_props(styles.red, bold && styles.bold))"
    >Red</span
  >
</template>
```

:::

---

---
url: /features/export-expose.md
---
# exportExpose&#x20;

Transform export statement as `defineExpose` params in Vue SFC `script-setup`.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    |         ?          |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

## Usage

Support these syntaxes:

* local variable/function/class
* export with alias
* export from other file
* namespace export
* rename export

### 1. local variable/function/class

```vue twoslash
<script setup lang="ts">
export const foo: string = 'foo'
export const bar = 10
export let baz: string | undefined
export var qux = fn()
// @errors: 2448 2454 2695
export const { a, b, c } = { a: 1, b: 2, c: 3 }

export function fn() {}
export class A {}
</script>
```

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const foo: string = 'foo'
const bar = 10
let baz: string | undefined
const qux = fn()
const { a, b, c } = { a: 1, b: 2, c: 3 }

function fn() {}
class A {}

defineExpose({
  foo,
  bar,
  baz,
  qux,
  a,
  b,
  c,
  fn,
  A,
})
</script>
```

:::

### 2. export with alias

```vue twoslash
<script setup lang="ts">
const foo = ''

export { foo as foo1 }
</script>
```

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const foo = 'foo'

defineExpose({
  foo1: foo,
})
</script>
```

:::

### 3. export from other file

::: code-group

```vue [App.vue] twoslash
<script setup lang="ts">
// #region export-file
const foo = 'foo'
type Foo = string

export { foo, type Foo }
// #endregion export-file
// ---cut---
// @noErrors
export { foo as bar, foo, type Foo } from './types'
</script>
```

<<< ./export-expose.md#export-file{ts} \[types.ts]

:::

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const __MACROS_expose_0 = 'foo'
const __MACROS_expose_1 = 'foo'
type Foo = string
// ---cut---
// @noErrors
import {
  foo as __MACROS_expose_0,
  foo as __MACROS_expose_1,
  type Foo,
} from './types'
defineExpose({
  foo: __MACROS_expose_0,
  bar: __MACROS_expose_1,
})
</script>
```

:::

### 4. namespace export

::: code-group

```vue [App.vue] twoslash
<script setup lang="ts">
const foo = { foo: 'foo' }
// ---cut---
// @noErrors
export * as foo from './types'
</script>
```

```ts [types.ts]
export const foo = 'foo'
```

:::

::: details Compiled Code

```vue twoslash
<script setup lang="ts">
const __MACROS_expose_0 = {
  foo: 'foo',
}
// ---cut---
// @noErrors
import * as __MACROS_expose_0 from './types'
defineExpose({
  foo: __MACROS_expose_0,
})
</script>
```

:::

### 5. rename export

```vue
<script setup lang="ts">
const foo = 1
const bar = 1

export { foo } from './types'
export * as bar from './types'
</script>
```

::: details Compiled Code

```vue
<script setup lang="ts">
import { foo as __MACROS_expose_0 } from './types'
import * as __MACROS_expose_1 from './types'

const foo = 1
const bar = 1
defineExpose({
  foo: __MACROS_expose_0,
  bar: __MACROS_expose_1,
})
</script>
```

:::

## Limitations

Currently does't support these following cases:

```ts
// 1. export all ❌
export * from '../types'

// 2. export default ❌
const a = 'a'
export default a
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "exportExpose": true,
    },
  },
}
```

---

---
url: /features/export-props.md
---
# exportProps&#x20;

[Svelte-like Declaring props](https://svelte.dev/docs#component-format-script-1-export-creates-a-component-prop) for Vue.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    |     :question:     |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

## Pre-requisite

[Reactivity Transform](./reactivity-transform.md) is required to use this feature, but it is enabled by default in Vue Macros.

`export let` will be changed to `defineModel`, which is supported in Vue 3.4+.

## Usage

Using export syntax to declare props.

```vue twoslash
<script setup lang="ts">
export let foo: string
export const bar: number = 1 // with default value
</script>
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "exportProps": true,
    },
  },
}
```

---

---
url: /features/export-render.md
---
# exportRender&#x20;

Transform the default export statement, in `<script setup>` of Vue SFC, as a component render function.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    |     :question:     |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

::: tip

This feature depends on `defineRender`, and make sure `defineRender` is not disabled.

:::

## Usage

```vue
<script setup lang="tsx">
// JSX passed directly
export default <div>ok</div>

// Or using render function
export default () => <div>ok</div>
</script>
```

## Volar Configuration

```jsonc {3,7} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "exportRender": true,
    },
  },
}
```

---

---
url: /guide/getting-started.md
---
# Getting Started

Vue Macros is a library that implements unofficial proposals and ideas for Vue,
exploring and extending its features and syntax.

We assume you are already familiar with the basic usages of Vue before you continue.

## Requirements

* Node.js `>= v20.19.0`.
* Vue `>= v2.7` or Vue `>= v3.0`.
  * Some features need Vue `>= v3.2.25`.
* VSCode extension [Vue - Official](https://marketplace.visualstudio.com/items?itemName=Vue.volar) and `vue-tsc` are v{{ version }}
  * Vue Macros will continue to adapt to the latest version as soon as possible, older versions may not be supported.

::: warning
WebStorm is not supported.
:::

## Creating a Vue Macros Project

### Installation

::: code-group

```bash [npm]
npm i -g @vue-macros/cli
```

```bash [yarn]
yarn global add @vue-macros/cli
```

```bash [pnpm]
pnpm add -g @vue-macros/cli
```

:::

This command will install [@vue-macros/cli](https://github.com/vue-macros/vue-macros-cli), the official Vue Macros scaffolding tool.

### Initialization

::: code-group

```bash [npm]
npm create vite@latest my-vue-macros -- --template vue-ts
cd my-vue-macros
vue-macros init
```

```bash [yarn]
yarn create vite my-vue-macros --template vue-ts
cd my-vue-macros
vue-macros init
```

```bash [pnpm]
pnpm create vite my-vue-macros --template vue-ts
cd my-vue-macros
vue-macros init
```

You will be presented with prompts for several optional experimental features.

:::

## Templates

* [Vite](https://github.com/vue-macros/vite)
* [Nuxt](https://github.com/vue-macros/nuxt)
* [Rsbuild](https://github.com/vue-macros/vue3-rsbuild)

🌟 More templates are welcome!

## Nuxt Integration

If you're using [Nuxt](https://nuxt.com/), read the [Nuxt Integration](./nuxt-integration.md).

## Bundler Integrations

If you're using [Vite](https://vitejs.dev/), [Rollup](https://rollupjs.org/), [esbuild](https://esbuild.github.io/), [Webpack](https://webpack.js.org/), or [Rspack](https://www.rspack.dev/), read the [Bundler Integration](./bundler-integration.md).

---

---
url: /features/hoist-static.md
---
# hoistStatic&#x20;

With enabling `hoistStatic`, constants declared in macros of `<script setup>` can be referenced.

For Vue >= 3.3, this feature will be turned off by default.

| Features |     Supported      |
| :------: | :----------------: |
|  Vue 3   | :white\_check\_mark: |
|  Nuxt 3  | :white\_check\_mark: |
|  Vue 2   | :white\_check\_mark: |

## Basic Usage

```vue twoslash
<script setup lang="ts">
const name = 'AppFoo'
defineOptions({
  name,
})
</script>
```

::: details Compiled Code

```vue
<script lang="ts">
const name = 'AppFoo'
export default {
  name,
}
</script>
```

:::

## Magic Comments

```vue
<script setup lang="ts">
// A value that's even not a constant
const name = /* hoist-static */ fn()
defineOptions({
  name,
})
</script>
```

::: details Compiled Code

```vue
<script lang="ts">
const name = fn()
export default {
  name,
}
</script>
```

:::

---

---
url: /features/jsx-directive.md
---
# jsxDirective&#x20;

Vue built-in directives for JSX.

|  Directive  |       Vue 3        |       Vue 2        |       Volar        |
| :---------: | :----------------: | :----------------: | :----------------: |
|   `v-if`    | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
| `v-else-if` | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|  `v-else`   | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|   `v-for`   | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|   `v-on`    | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|  `v-slot`   | :white\_check\_mark: | :white\_check\_mark: | :white\_check\_mark: |
|  `v-html`   | :white\_check\_mark: | :white\_check\_mark: |         /          |
|  `v-once`   | :white\_check\_mark: |        :x:         |         /          |
|  `v-memo`   | :white\_check\_mark: |        :x:         |         /          |

## Options

```ts
interface Options {
  /**
   * @default 'v-'
   */
  prefix?: string
  /**
   * @default 'vue'
   */
  lib?: 'vue' | 'react' | 'preact' | 'solid' | string
}
```

## Usage

### `v-if`, `v-else-if`, `v-else`

```vue twoslash
<script setup lang="tsx">
const { foo } = defineProps<{
  foo: number
}>()

// ---cut-start---
// prettier-ignore
// ---cut-end---
export default () => (
  <>
    <div v-if={foo === 0}>{foo}</div>

    <div v-else-if={foo === 1}>{foo}</div>
    //                          ^?

    <div v-else>{foo}</div>
    //           ^?
  </>
)
</script>
```

### `v-for`

```vue twoslash
<script setup lang="tsx">
export default () => (
  <div v-for={(item, index) in 4} key={index}>
    {item}
  </div>
)
</script>
```

### `v-slot`

::: code-group

```vue [App.vue] twoslash
<script lang="tsx" setup>
// #region v-slot
import type { FunctionalComponent } from 'vue'

export const Comp: FunctionalComponent<
  {},
  {},
  {
    default: () => any
    slot: (scope: { bar: number }) => any
    slots: (scope: { baz: boolean }) => any
  }
> = () => <div />
// #endregion v-slot
// ---cut---
// @noErrors
import { Comp } from './Comp.tsx'

// ---cut-start---
// prettier-ignore
// ---cut-end---
export default () => (
  <Comp>
    default slot...
    <template v-slot:slot={{ bar }}>
      //              ^|
      {bar}
    </template>
  </Comp>
)
</script>
```

<<< ./jsx-directive.md#v-slot{tsx} \[Child.tsx]

:::

### `v-on`

::: warning

`v-on` only supports binding to an object of event / listener pairs without an argument.

:::

```tsx
<form v-on={{ submit }} />
```

## Dynamic Arguments

It is also possible to use a variable in a directive argument by wrapping it with a pair of `


  
  
  
  
  vue-macros.dev | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


  :

`v-model`

::: code-group

```vue [App.vue] twoslash
<script setup lang="tsx">
// ---cut-start---
// #region v-model
import { ref, type FunctionalComponent } from 'vue'

export const Comp: FunctionalComponent<
  {
    model: string
    models: string[]
  },
  {
    'update:model': [value: string]
    'update:models': [value: string[]]
  }
> = () => <div />
// #endregion v-model
// ---cut-end---
// @noErrors
import { Comp } from './Comp.tsx'

const name = ref('model')
const model = defineModel<string>()

export default () => (
  <Comp
    v-model:$name$={model.value}
    v-model:model={model.value}
    //       ^|
  />
)
</script>
```

<<< ./jsx-directive.md#v-model{tsx} \[Comp.tsx]

:::

`v-slot`

::: code-group

```vue [App.vue] twoslash
<script setup lang="tsx">
// ---cut-start---
// #region v-slot-dynamic
import type { FunctionalComponent } from 'vue'

export const Comp: FunctionalComponent<
  {},
  {},
  {
    default: (scope: { foo: string }) => any
    title: (scope: { bar: number }) => any
  }
> = () => <div />
// #endregion v-slot-dynamic
// ---cut-end---
// @noErrors
import { Comp } from './Comp.tsx'

const slots = defineSlots<{
  default: (scope: { foo: string }) => any
  title: (scope: { bar: number }) => any
}>()

// ---cut-start---
// prettier-ignore
// ---cut-end---
export default () => (
  <Comp>
    <template v-for={(Slot, name) in slots} v-slot:$name$={scope}>
      //                                             ^?
      <Slot {...scope} />
    </template>
  </Comp>
)
</script>
```

<<< ./jsx-directive.md#v-slot-dynamic{tsx} \[Comp.tsx]

:::

## Modifiers

Modifiers are special postfixes denoted by a `_`, which indicate that a directive should be bound in some special way.

```tsx
<form onSubmit_prevent>
  <input v-model_number={value} />
</form>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /volar/jsx-ref.md
---
# jsxRef&#x20;

Automatically infer type for `useRef`.

| Features |     Supported      |
| :------: | :----------------: |
|  Volar   | :white\_check\_mark: |

## Setup Auto Import

::: code-group

```ts [vite.config.ts]
import AutoImport from 'unplugin-auto-import/vite'

export default defineConfig({
  plugins: [
    AutoImport({
      imports: [
        {
          from: 'vue',
          imports: [['shallowRef', 'useRef']],
        },
      ],
    }),
  ],
})
```

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  imports: {
    presets: [
      {
        from: 'vue',
        imports: [['shallowRef', 'useRef']],
      },
    ],
  },
})
```

:::

## Basic Usage

::: code-group

```vue [App.vue] twoslash
<script lang="tsx">
// #region comp
import { defineComponent } from 'vue'

export const Comp = defineComponent({
  setup() {
    return { foo: 1 }
  },
})
// #endregion comp
// ---cut---
import { useRef } from 'vue-macros/runtime'
// Or import { shallowRef as useRef } from 'vue'
// @noErrors
import { Comp } from './Comp.ts'

export default defineComponent(() => {
  const comp = useRef()
  comp.value?.foo
  //           ^?

  return () => (
    <>
      <Comp ref={comp} />
    </>
  )
})
</script>
```

<<< ./jsx-ref.md#comp{ts} \[Comp.ts]

:::

## Volar Configuration

```jsonc [tsconfig.json] {3,6}
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "jsxRef": {
        "alias": ["useRef"],
      },
    },
  },
}
```

---

---
url: /guide/migration-v3.md
---
# Migration from v2 to v3

## Unified Version Management

Initially, we used [`changesets`](https://github.com/changesets/changesets) to
manage the versions of all packages in the monorepo. However, after two years of experimentation,
we decided to adopt a single-version strategy in v3,
where all sub-packages share the same version number, similar to Vue and Babel.
This decision stemmed from our observation that when a sub-package underwent a major change or minor update,
the version number of the main package did not adequately reflect these changes.

For example, when `@vue-macros/define-prop` introduced a breaking change,
how should `unplugin-vue-macros` release a new version?
Should it be a minor or a patch release? When users updated `unplugin-vue-macros`,
they couldn’t easily determine whether the update was due to changes in `@vue-macros/define-prop`.

Therefore, after Anthony proposed [Epoch Semantic Versioning](https://antfu.me/posts/epoch-semver),
we decided to adopt a more frequent major version update strategy,
with all packages sharing the same version number and maintaining a single unified changelog.

## Main Package Rename

We have renamed the main package from `unplugin-vue-macros` to **`vue-macros`**.
After the official release of v3, `unplugin-vue-macros` will be marked as deprecated.

As a result, you will need to update your `package.json` and the import statements for Vue Macros:

```diff
 // package.json
 {
   "devDependencies": {
-    "unplugin-vue-macros": "^2.14.5"
+    "vue-macros": "^3.0.0"
   }
 }
```

```diff
- import { $ref } from 'unplugin-vue-macros/macros'
+ import { $ref } from 'vue-macros/macros'

- import VueMacros from 'unplugin-vue-macros/vite'
+ import VueMacros from 'vue-macros/vite'
```

## Dropping Vue 2 Support

Vue 2 reached its end of life (EOL) at the end of 2023, so we have decided to drop support for Vue 2 in v3.
If you are still using Vue 2, we recommend continuing with v2 or
considering our [paid support plan](https://github.com/vue-macros/vue-macros/issues/373).

## Node.js Compatibility Changes

In v3, we have dropped support for Node.js versions below 20.19.
This means the minimum Node.js version requirement for v3 is `20.19.0`.
Additionally, we have removed CommonJS (CJS) outputs and now only provide ECMAScript modules (ESM).

## Dropping Webpack 4 Support

Since Webpack 4 cannot run in Node.js 18 or later environments,
we have also dropped support for Webpack 4 and Vue CLI 4.
We recommend upgrading to modern build tools like Vite or Rspack.

---

---
url: /features/named-template.md
---
# namedTemplate&#x20;

::: warning

Not actively maintained now. Try [createReusableTemplate](https://vueuse.org/core/createReusableTemplate/) instead.

:::

With enabling `namedTemplate`, `<template>` can be referenced like a variable.

Sometimes we need to reverse the order of the very simple components, and don't want to give the features of Vue template up and use JSX/TSX. Then this feature is much helpful.

If you support this feature, you can go to [the discussion](https://github.com/vuejs/core/discussions/6898) and hit like :+1: or comment.

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|      Vue 3.3       |        :x:         |
|       Nuxt 3       |        :x:         |
|       Vue 2        |        :x:         |
| TypeScript / Volar |        :x:         |

## Basic Usage

```vue {5-7,10-12,16-18}
<script setup>
const pager = 'top'
</script>

<template name="pager">
  <span>This is pager</span>
</template>

<template>
  <template v-if="pager === 'top'">
    <template is="pager" />
  </template>

  <span>Here is data table</span>

  <template v-if="pager === 'bottom'">
    <template is="pager" />
  </template>
</template>
```

## Known Usage

* TypeScript / Volar support is not yet completed.

---

---
url: /features/reactivity-transform.md
---
# Reactivity Transform&#x20;

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|       Nuxt 3       | :white\_check\_mark: |
|       Vue 2        | :white\_check\_mark: |
| TypeScript / Volar | :white\_check\_mark: |

## Installation Standalone Version

if you need Reactivity Transform feature only, the standalone version is more appropriate for you.

### Installation

::: code-group

```bash [npm]
npm i -D @vue-macros/reactivity-transform
```

```bash [yarn]
yarn add -D @vue-macros/reactivity-transform
```

```bash [pnpm]
pnpm add -D @vue-macros/reactivity-transform
```

:::

::: code-group

```ts [Vite]
// vite.config.ts
import ReactivityTransform from '@vue-macros/reactivity-transform/vite'

export default defineConfig({
  plugins: [ReactivityTransform()],
})
```

```ts [Rollup]
// rollup.config.js
import ReactivityTransform from '@vue-macros/reactivity-transform/rollup'

export default {
  plugins: [ReactivityTransform()],
}
```

```js [esbuild]
// esbuild.config.js
import { build } from 'esbuild'

build({
  plugins: [require('@vue-macros/reactivity-transform/esbuild')()],
})
```

```js [Webpack]
// webpack.config.js
module.exports = {
  /* ... */
  plugins: [require('@vue-macros/reactivity-transform/webpack')()],
}
```

:::

### TypeScript Support

```json [tsconfig.json]
{
  "compilerOptions": {
    // ...
    "types": ["@vue-macros/reactivity-transform/macros-global" /* ... */]
  }
}
```

## Refs vs. Reactive Variables {#refs-vs-reactive-variables}

Ever since the introduction of the Composition API, one of the primary unresolved questions is the use of refs vs. reactive objects. It's easy to lose reactivity when destructuring reactive objects, while it can be cumbersome to use `.value` everywhere when using refs. Also, `.value` is easy to miss if not using a type system.

Reactivity Transform is a compile-time transform that allows us to write code like this:

```vue twoslash
<script setup>
let count = $ref(0)

console.log(count)

function increment() {
  count++
}
</script>

<template>
  <button @click="increment">{{ count }}</button>
</template>
```

The `$ref()` method here is a **compile-time macro**: it is not an actual method that will be called at runtime. Instead, the Vue compiler uses it as a hint to treat the resulting `count` variable as a **reactive variable.**

Reactive variables can be accessed and re-assigned just like normal variables, but these operations are compiled into refs with `.value`. For example, the `<script>` part of the above component is compiled into:

```js{5,8} twoslash
import { ref } from 'vue'

let count = ref(0)

console.log(count.value)

function increment() {
  count.value++
}
```

Every reactivity API that returns refs will have a `


  
  
  
  
  vue-macros.dev | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


  -prefixed macro equivalent. These APIs include:

* [`ref`](https://vuejs.org/api/reactivity-core#ref) -> `$ref`
* [`computed`](https://vuejs.org/api/reactivity-core#computed) -> `$computed`
* [`shallowRef`](https://vuejs.org/api/reactivity-advanced#shallowref) -> `$shallowRef`
* [`customRef`](https://vuejs.org/api/reactivity-advanced#customref) -> `$customRef`
* [`toRef`](https://vuejs.org/api/reactivity-utilities#toref) -> `$toRef`

These macros are globally available and do not need to be imported when Reactivity Transform is enabled, but you can optionally import them from `vue-macros/macros` or `@vue-macros/reactivity-transform/macros-global` if you want to be more explicit:

```js twoslash
import { $ref } from 'vue-macros/macros'
// for standalone version:
// import { $ref } from '@vue-macros/reactivity-transform/macros-global'

const count = $ref(0)
```

## Destructuring with `$()` {#destructuring-with}

It is common for a composition function to return an object of refs, and use destructuring to retrieve these refs. For this purpose, reactivity transform provides the **`$()`** macro:

```js twoslash
import { ref } from 'vue'
function useMouse() {
  return {
    x: ref(0),
    y: ref(0),
  }
}
// ---cut---
const { x, y } = $(useMouse())

console.log(x, y)
```

Compiled output:

```js twoslash
import { ref, toRef } from 'vue'
function useMouse() {
  return {
    x: ref(0),
    y: ref(0),
  }
}
// ---cut---
const __temp = useMouse()
const x = toRef(__temp, 'x')
const y = toRef(__temp, 'y')

console.log(x.value, y.value)
```

Note that if `x` is already a ref, `toRef(__temp, 'x')` will simply return it as-is and no additional ref will be created. If a destructured value is not a ref (e.g. a function), it will still work - the value will be wrapped in a ref so the rest of the code works as expected.

`$()` destructure works on both reactive objects **and** plain objects containing refs.

## Convert Existing Refs to Reactive Variables with `$()` {#convert-existing-refs-to-reactive-variables-with}

In some cases we may have wrapped functions that also return refs. However, the Vue compiler won't be able to know ahead of time that a function is going to return a ref. In such cases, the `$()` macro can also be used to convert any existing refs into reactive variables:

```js twoslash
import { ref } from 'vue'

function myCreateRef() {
  return ref(0)
}

const count = $(myCreateRef())
```

## Reactive Props Destructure {#reactive-props-destructure}

There are two pain points with the current `defineProps()` usage in `<script setup>`:

1. Similar to `.value`, you need to always access props as `props.x` in order to retain reactivity. This means you cannot destructure `defineProps` because the resulting destructured variables are not reactive and will not update.

2. When using the [type-only props declaration](https://vuejs.org/api/sfc-script-setup.html#typescript-only-features), there is no easy way to declare default values for the props. We introduced the `withDefaults()` API for this exact purpose, but it's still clunky to use.

We can address these issues by applying a compile-time transform when `defineProps` is used with destructuring, similar to what we saw earlier with `$()`:

```vue twoslash
<script setup lang="ts">
import { watchEffect } from 'vue'

interface Props {
  msg: string
  count?: number
  foo?: string
}

const {
  msg,
  // default value just works
  count = 1,
  // local aliasing also just works
  // here we are aliasing `props.foo` to `bar`
  foo: bar,
} = defineProps<Props>()

watchEffect(() => {
  // will log whenever the props change
  console.log(msg, count, bar)
})
</script>
```

The above will be compiled into the following runtime declaration equivalent:

```ts twoslash
import { defineComponent, watchEffect } from 'vue'

export default defineComponent({
  props: {
    msg: { type: String, required: true },
    count: { type: Number, default: 1 },
    foo: String,
  },
  setup(props) {
    watchEffect(() => {
      console.log(props.msg, props.count, props.foo)
    })
  },
})
```

## Retaining Reactivity Across Function Boundaries {#retaining-reactivity-across-function-boundaries}

While reactive variables relieve us from having to use `.value` everywhere, it creates an issue of "reactivity loss" when we pass reactive variables across function boundaries. This can happen in two cases:

### Passing into function as argument {#passing-into-function-as-argument}

Given a function that expects a ref as an argument, e.g.:

```ts twoslash
import { watch, type Ref } from 'vue'

function trackChange(x: Ref<number>) {
  watch(x, (x) => {
    console.log('x changed!')
  })
}

const count = $ref(0)
// @errors: 2345
trackChange(count) // doesn't work!
```

The above case will not work as expected because it compiles to:

```ts
const count = ref(0)
trackChange(count.value)
```

Here `count.value` is passed as a number, whereas `trackChange` expects an actual ref. This can be fixed by wrapping `count` with `$()` before passing it:

```diff
let count = $ref(0)
- trackChange(count)
+ trackChange($(count))
```

The above compiles to:

```js
import { ref } from 'vue'

const count = ref(0)
trackChange(count)
```

As we can see, `$()` is a macro that serves as an **escape hint**: reactive variables inside `$()` will not get `.value` appended.

### Returning inside function scope {#returning-inside-function-scope}

Reactivity can also be lost if reactive variables are used directly in a returned expression:

```ts twoslash
function useMouse() {
  const x = $ref(0)
  const y = $ref(0)

  // listen to mousemove...

  // doesn't work!
  return {
    x,
    y,
  }
}
```

The above return statement compiles to:

```ts
return {
  x: x.value,
  y: y.value,
}
```

In order to retain reactivity, we should be returning the actual refs, not the current value at return time.

Again, we can use `$()` to fix this. In this case, `$()` can be used directly on the returned object - any reference to reactive variables inside the `$()` call will retain the reference to their underlying refs:

```ts twoslash
function useMouse() {
  const x = $ref(0)
  const y = $ref(0)

  // listen to mousemove...

  // fixed
  return $({
    x,
    y,
  })
}
```

### Using `$()` on destructured props {#using-on-destructured-props}

`$()` works on destructured props since they are reactive variables as well. The compiler will convert it with `toRef` for efficiency:

```vue twoslash
<script setup lang="ts">
import type { Ref } from 'vue'
function passAsRef(count: Ref<number>) {
  return count
}
// ---cut---
const { count } = defineProps<{ count: number }>()

passAsRef($(count))
</script>
```

compiles to:

```ts twoslash
import { defineComponent, toRef, type Ref } from 'vue'
function passAsRef(count: Ref<number>) {
  return count
}
// ---cut---
export default defineComponent({
  props: {
    count: { type: Number, required: true },
  },
  setup(props) {
    const __props_count = toRef(props, 'count')
    passAsRef(__props_count)
  },
})
```

## TypeScript Integration  {#typescript-integration}

Vue provides typings for these macros (available globally) and all types will work as expected. There are no incompatibilities with standard TypeScript semantics, so the syntax will work with all existing tooling.

This also means the macros can work in any files where valid JS / TS are allowed - not just inside Vue SFCs.

Since the macros are available globally, their types need to be explicitly referenced (e.g. in a `env.d.ts` file):

```ts [env.d.ts]
/// <reference types="vue-macros/macros-global" />

// or for standalone version:
/// <reference types="@vue-macros/reactivity-transform/macros-global" />
```

When explicitly importing the macros from `vue-macros/macros` or `@vue-macros/reactivity-transform/macros-global`, the type will work without declaring the globals.

---

---
url: /features/script-lang.md
---
# scriptLang&#x20;

Set the default language for `<script>` block.

::: tip
Convert `<script setup>` to `<script setup lang="ts">`.
:::

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     | :white\_check\_mark: |
| Volar Plugin | :white\_check\_mark: |

## Options

```ts
interface Options {
  /**
   * @default 'ts'
   */
  defaultLang?: 'ts' | 'tsx' | 'jsx' | string
}
```

## Usage

```vue twoslash
<script setup>
defineProps<{
  foo: string
}>()
</script>
```

## Volar Configuration

```jsonc {3,5-7} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "scriptLang": {
        "defaultLang": "ts",
      },
    },
  },
}
```

---

---
url: /volar/script-sfc.md
---
# scriptSFC&#x20;

Enabled Volar support for `.ts` | `.tsx` files.

|   Features   |     Supported      |
| :----------: | :----------------: |
| Volar Plugin | :white\_check\_mark: |

## Basic Usage

### With `jsxDirective`

::: code-group

```tsx [App.tsx]
export default ({ foo }: { foo: number }) => (
  <div v-if={foo === 1}>{foo}</div>
  //                     ^ will be inferred as 1
)
```

:::

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["@vue-macros/volar"],
    "vueMacros": {
      "scriptSFC": true,
    },
  },
}
```

---

---
url: /macros/setup-component.md
---
# setupComponent&#x20;

::: tip

`defineRender` cannot be disabled when using `setupComponent`.

Files in `node_modules` will be ignored by default.

:::

With `defineSetupComponent`, `<script setup>` code can be put in **pure JS/TS(X)** without [Vue Language Tools (Volar)](https://github.com/johnsoncodehk/volar) extension.

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Nuxt 3   |        :x:         |
|   Vue 2    |        :x:         |
| TypeScript |        :x:         |

See also [Vue Vine](https://vue-vine.dev/) - another style for Vue functional component.

## Basic Usage

```tsx twoslash
export const App = defineSetupComponent(() => {
  defineProps<{
    foo: string
  }>()

  defineEmits<{
    (evt: 'change'): void
  }>()

  defineOptions({
    name: 'App',
  })

  // ...
  return <div />
})
```

## Type Annotation

```ts twoslash
export const App: SetupFC = () => {
  defineProps<{
    foo: string
  }>()

  defineEmits<{
    (evt: 'change'): void
  }>()

  defineOptions({
    name: 'App',
  })
}
```

## Known Issues

* TypeScript support is not yet completed.
* The source map does not correspond properly.

---

---
url: /volar/setup-jsdoc.md
---
# setupJsdoc&#x20;

Define the component's JSDoc in the script setup block.

|   Features   |     Supported      |
| :----------: | :----------------: |
| Volar Plugin | :white\_check\_mark: |

## Basic Usage

````vue twoslash
<script setup lang="tsx">
/**
 * @example
 * ```vue
 * <Comp :foo="1" />
 * ```
 */
const Comp = () => <div />
// ---cut---
// @noErrors
import Comp from './Comp.vue'
//     ^?
</script>

<template>
  <Comp />
</template>
````

### There are two places to define

1. The first line of the script setup block.

````vue
<script setup lang="ts">
/**
 * @example
 * ```vue
 * <Comp :foo="1" />
 * ```
 */

defineProps<{
  foo: number
}>()
</script>
````

2. Above the `export default` expression.

::: tip

This feature depends on `exportRender`, and make sure `exportRender` is not disabled.

:::

````vue
<script setup lang="tsx">
defineProps<{
  foo: number
}>()

/**
 * @example
 * ```vue
 * <Comp :foo="1" />
 * ```
 */
export default <div />
</script>
````

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/setup-sfc.md
---
# setupSFC&#x20;

::: tip

If you're using `setupSFC`, then `defineRender` cannot be disabled.

:::

|      Features      |     Supported      |
| :----------------: | :----------------: |
|       Vue 3        | :white\_check\_mark: |
|       Nuxt 3       | :white\_check\_mark: |
|       Vue 2        | :white\_check\_mark: |
| TypeScript / Volar | :white\_check\_mark: |

## Setup

::: code-group

```ts {7-14} [Vite]
// vite.config.ts
import Vue from '@vitejs/plugin-vue'
import VueMacros from 'vue-macros/vite'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue({
          include: [/\.vue$/, /\.setup\.[cm]?[jt]sx?$/],
          //                   ⬆️ setupSFC pattern need to be added
        }),
      },
    }),
  ],
})
```

```ts {6-13} [Rollup]
import Vue from 'unplugin-vue/rollup'
import VueMacros from 'vue-macros/rollup'

export default defineConfig({
  plugins: [
    VueMacros({
      plugins: {
        vue: Vue({
          include: [/\.vue$/, /\.setup\.[cm]?[jt]sx?$/],
          //                   ⬆️ setupSFC pattern need to be added
        }),
      },
    }),
  ],
})
```

```[🚧 esbuild]
🚧
```

```[🚧 Webpack]
🚧
```

:::

## Basic Usage

```tsx twoslash
// Foo.setup.tsx
defineProps<{
  foo: string
}>()

defineEmits<{
  (evt: 'change'): void
}>()

export default () => (
  <div>
    <h1>Hello World</h1>
  </div>
)
```

## Volar Configuration

```jsonc {3,5} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
    "vueMacros": {
      "setupSFC": true,
    },
  },
}
```

---

---
url: /features/short-bind.md
---
# shortBind&#x20;

`:value` -> `:value="value"`

Same-name shorthand for binding prop. If the attribute has the same name with the JavaScript value being bound, the syntax can be further shortened to omit the attribute value.

For Vue >= 3.4, this feature will be turned off by default.

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     |        :x:         |
| Volar Plugin | :white\_check\_mark: |

## Usage

### Basic Usage

```vue twoslash
<script setup>
const value = 'foo'
</script>

<template>
  <input :value />
  <!-- => <input :foo="value" /> -->
</template>
```

### With `shortVmodel`

```vue
<template>
  <Comp ::value />
  <!-- => <Comp ::foo="foo" /> => <Comp v-model:foo="foo" /> -->
  <Comp $foo />
  <!-- => <Comp $foo="foo" /> => <Comp v-model:foo="foo" /> -->
  <Comp *foo />
  <!-- => <Comp *foo="foo" /> => <Comp v-model:foo="foo" /> -->
</template>
```

## Volar Configuration

```jsonc {3} [tsconfig.json]
{
  "vueCompilerOptions": {
    "plugins": ["vue-macros/volar"],
  },
}
```

---

---
url: /macros/short-emits.md
---
# shortEmits&#x20;

Simplify the definition of emits.

For Vue >= 3.3, this feature will be turned off by default.

|  Features  |     Supported      |
| :--------: | :----------------: |
|   Vue 3    | :white\_check\_mark: |
|   Vue 2    | :white\_check\_mark: |
| TypeScript | :white\_check\_mark: |

## Basic Usage

```vue twoslash
<script setup lang="ts">
import { defineEmits } from 'vue-macros/macros'

const emits = defineEmits<{
  // tuple
  'update:modelValue': [val: string]
  // function
  update: (val: string) => void
}>()
</script>
```

Using type `ShortEmits` or for short `SE`.

```vue twoslash
<script setup lang="ts">
const emits = defineEmits<
  SE<{
    // tuple
    'update:modelValue': [val: string]
    // function
    update: (val: string) => void
  }>
>()
</script>
```

## Difference with Official Version

* function style of declaration is not supported by official version.

---

---
url: /macros/short-vmodel.md
---
# shortVmodel&#x20;

A shorthand for `v-model`.

`v-model` -> `::` / `


  
  
  
  
  vue-macros.dev | Top Sites | DialtoneApp
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


   / `*`

If you have any questions about this feature, you can comment on [RFC Discussion](https://github.com/vuejs/rfcs/discussions/395).

|   Features   |     Supported      |
| :----------: | :----------------: |
|    Vue 3     | :white\_check\_mark: |
|    Nuxt 3    | :white\_check\_mark: |
|    Vue 2     |        :x:         |
| Volar Plugin | :white\_check\_mark: |

## Options

```ts
interface Options {
  /**
   * @default '
#x27; */ prefix?: '::' | '
#x27; | '*' } ``` ## Usage ### ` vue-macros.dev | Top Sites | DialtoneApp Dollar Sign (Default) ```vue <template> <input $="msg" /> <!-- => <input v-model="msg" /> --> <demo $msg="msg" /> <!-- => <input v-model:msg="msg" /> --> </template> ``` ### `::` Double Binding ```vue <template> <!-- prettier-ignore --> <input ::="msg" /> <!-- => <input v-model="msg" /> --> <demo ::msg="msg" /> <!-- => <input v-model:msg="msg" /> --> </template> ``` ### `*` Asterisk Sign ```vue <template> <input *="msg" /> <!-- => <input v-model="msg" /> --> <demo *msg="msg" /> <!-- => <input v-model:msg="msg" /> --> </template> ``` ## Volar Configuration ```jsonc {3,5-7} [tsconfig.json] { "vueCompilerOptions": { "plugins": ["vue-macros/volar"], "vueMacros": { "shortVmodel": { "prefix": "
quot;, }, }, }, } ``` ## Known Issues * Prettier will format `::=` to `:=` (e.g. `<div ::="msg" />` -> `<div :="msg" />`). The comment `<!-- prettier-ignore -->` is required if prefix is `::`. --- --- url: /volar/template-ref.md --- # templateRef&#x20; Automatically infer type for `templateRef` (from [VueUse](https://vueuse.org/core/templateRef/)) and `useTemplateRef` (Vue 3.5+). ::: warning This feature is officially supported since Volar (`vue-tsc`) v2.1.0. Vue Macros is no longer offering this feature as a plugin. ::: | Features | Supported | | :------: | :----------------: | | Volar | :white\_check\_mark: | ## Basic Usage ::: code-group ```vue [App.vue] twoslash <script setup lang="ts"> // #region comp import { defineComponent } from 'vue' export const Comp = defineComponent({ setup() { return { foo: 1 } }, }) // #endregion comp // ---cut--- import { templateRef } from '@vueuse/core' // @noErrors import { Comp } from './Comp.ts' const comp = templateRef('comp') comp.value?.foo // ^? </script> <template> <Comp ref="comp" /> </template> ``` <<< ./template-ref.md#comp{ts} \[Comp.ts] ::: ## Volar Configuration No configuration required. --- --- url: /macros.md --- # Usage List of all available macros. Please make sure `vue-macros` is set up correctly. If you haven't yet, read [Getting Started](../guide/getting-started.md) first. ## Implemented by Vue 3.3 * [defineOptions](./define-options.md) * [defineSlots](./define-slots.md) * [shortEmits](./short-emits.md) ## Stable Features * [defineModels](./define-models.md) * [defineProps](./define-props.md) * [definePropsRefs](./define-props-refs.md) * [defineRender](./define-render.md) * [shortVmodel](./short-vmodel.md) ## Experimental Features * [defineProp](./define-prop.md) * [defineEmit](./define-emit.md) * [setupComponent](./setup-component.md) * [setupSFC](./setup-sfc.md) * [chainCall](./chain-call.md) * [defineStyleX](./define-stylex.md)
Dollar Sign (Default)\n\n```vue\n\u003ctemplate\u003e\n \u003cinput $=\"msg\" /\u003e\n \u003c!-- =\u003e \u003cinput v-model=\"msg\" /\u003e --\u003e\n \u003cdemo $msg=\"msg\" /\u003e\n \u003c!-- =\u003e \u003cinput v-model:msg=\"msg\" /\u003e --\u003e\n\u003c/template\u003e\n```\n\n### `::` Double Binding\n\n```vue\n\u003ctemplate\u003e\n \u003c!-- prettier-ignore --\u003e\n \u003cinput ::=\"msg\" /\u003e\n \u003c!-- =\u003e \u003cinput v-model=\"msg\" /\u003e --\u003e\n \u003cdemo ::msg=\"msg\" /\u003e\n \u003c!-- =\u003e \u003cinput v-model:msg=\"msg\" /\u003e --\u003e\n\u003c/template\u003e\n```\n\n### `*` Asterisk Sign\n\n```vue\n\u003ctemplate\u003e\n \u003cinput *=\"msg\" /\u003e\n \u003c!-- =\u003e \u003cinput v-model=\"msg\" /\u003e --\u003e\n \u003cdemo *msg=\"msg\" /\u003e\n \u003c!-- =\u003e \u003cinput v-model:msg=\"msg\" /\u003e --\u003e\n\u003c/template\u003e\n```\n\n## Volar Configuration\n\n```jsonc {3,5-7} [tsconfig.json]\n{\n \"vueCompilerOptions\": {\n \"plugins\": [\"vue-macros/volar\"],\n \"vueMacros\": {\n \"shortVmodel\": {\n \"prefix\": \"$\",\n },\n },\n },\n}\n```\n\n## Known Issues\n\n* Prettier will format `::=` to `:=` (e.g. `\u003cdiv ::=\"msg\" /\u003e` -\u003e `\u003cdiv :=\"msg\" /\u003e`). The comment `\u003c!-- prettier-ignore --\u003e` is required if prefix is `::`.\n\n---\n\n---\nurl: /volar/template-ref.md\n---\n# templateRef\u0026#x20;\n\nAutomatically infer type for `templateRef` (from [VueUse](https://vueuse.org/core/templateRef/))\nand `useTemplateRef` (Vue 3.5+).\n\n::: warning\n\nThis feature is officially supported since Volar (`vue-tsc`) v2.1.0.\nVue Macros is no longer offering this feature as a plugin.\n\n:::\n\n| Features | Supported |\n| :------: | :----------------: |\n| Volar | :white\\_check\\_mark: |\n\n## Basic Usage\n\n::: code-group\n\n```vue [App.vue] twoslash\n\u003cscript setup lang=\"ts\"\u003e\n// #region comp\nimport { defineComponent } from 'vue'\n\nexport const Comp = defineComponent({\n setup() {\n return { foo: 1 }\n },\n})\n// #endregion comp\n// ---cut---\nimport { templateRef } from '@vueuse/core'\n// @noErrors\nimport { Comp } from './Comp.ts'\n\nconst comp = templateRef('comp')\ncomp.value?.foo\n// ^?\n\u003c/script\u003e\n\n\u003ctemplate\u003e\n \u003cComp ref=\"comp\" /\u003e\n\u003c/template\u003e\n```\n\n\u003c\u003c\u003c ./template-ref.md#comp{ts} \\[Comp.ts]\n\n:::\n\n## Volar Configuration\n\nNo configuration required.\n\n---\n\n---\nurl: /macros.md\n---\n# Usage\n\nList of all available macros.\n\nPlease make sure `vue-macros` is set up correctly. If you haven't yet, read [Getting Started](../guide/getting-started.md) first.\n\n## Implemented by Vue 3.3\n\n* [defineOptions](./define-options.md)\n* [defineSlots](./define-slots.md)\n* [shortEmits](./short-emits.md)\n\n## Stable Features\n\n* [defineModels](./define-models.md)\n* [defineProps](./define-props.md)\n* [definePropsRefs](./define-props-refs.md)\n* [defineRender](./define-render.md)\n* [shortVmodel](./short-vmodel.md)\n\n## Experimental Features\n\n* [defineProp](./define-prop.md)\n* [defineEmit](./define-emit.md)\n* [setupComponent](./setup-component.md)\n* [setupSFC](./setup-sfc.md)\n* [chainCall](./chain-call.md)\n* [defineStyleX](./define-stylex.md)\n","robots_txt_url":null,"llms_txt_url":"/api/v1/crawler/top-sites/vue-macros.dev/llms.txt","llms_full_txt_url":"/api/v1/crawler/top-sites/vue-macros.dev/llms-full.txt"}}