Frontend Development 22 min read

Using JSX/TSX in Vue 3: Component Definition, Syntax, Props, Scoped CSS, and Slots

This article provides a comprehensive guide to using JSX/TSX in Vue 3, covering project setup, the defineComponent API, option and function syntax, data binding, event handling, slots, scoped CSS, and various approaches to defining and simplifying props with TypeScript.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Using JSX/TSX in Vue 3: Component Definition, Syntax, Props, Scoped CSS, and Slots

Preface

JSX syntax gives developers a comfortable experience; using JSX in Vue 3 combines JavaScript flexibility with Vue's reactivity, and migrating to TSX is straightforward.

Project Setup

Run npm init vue to create a Vue project.

Project Repository

The example project can be found at https://gitee.com/z-shichao/vue_tsx .

Component Definition: defineComponent

In Vue 3, defineComponent is a function API for defining components. It provides three main capabilities:

Creating the component options object: defineComponent lets you define an object containing props, methods, lifecycle hooks, etc.

Type inference support: using defineComponent helps TypeScript infer component types, improving development efficiency and code robustness.

Providing a unified component definition context: internally it processes the options object, converts lifecycle hooks, compiles templates, and offers a clear, consistent component definition.

See a dedicated article: https://juejin.cn/post/6994617648596123679

TSX Syntax

TSX supports two writing modes: option syntax and function syntax.

// Option syntax
import
{ defineComponent }
from
"vue"
export
default
defineComponent({
  setup() {
return
() => (
vue3+tsx
)
  }
})
// Function syntax
export
default
defineComponent(() => {
return
() => (
vue3+tsx
)
})

Choosing between option and function syntax depends on personal habit; the following examples use option syntax.

Note: The returned value is a function that returns a JSX element. JSX elements must have a single root tag. If you do not want a root tag, you can use <></> , which does not render in the page.

Interpolation Syntax

export
default
defineComponent({
  setup() {
let
text = ref<string>('我是文本内容')
return
() => (
{text.value}
)
  }
})

Note: When defining reactive data with ref , you need to access the value using .value in the template.

Event Binding

export
default
defineComponent({
  setup() {
let
text = '我是文本内容'
return
() => (
      <>
{text}
{ alert('您点击了我') }}>点我
)
  }
})

Event Modifiers

Add camelCase event modifiers.

export
default
defineComponent({
  setup() {
let
text = '我是文本内容'
return
() => (
      <>
{text}
{ alert('您点击了我') }}>点我
)
  }
})

Note: Use curly braces {} for interpolation, and on+eventName (camelCase) for event binding; custom events follow the same pattern.

JSX Removes Some Directives: v-bind, v-for, v-if

v-bind : use curly braces {} to wrap.

export
default
defineComponent({
  setup() {
let
text = '我是文本内容'
let
style = { background: 'red' }
return
() => (
      <>
{text}
{ alert('您点击了我') }}>点我
)
  }
})

v-for : use array method map .

export
default
defineComponent({
  setup() {
let
items = ['张三', '李四', '王五']
return
() => (
      <>
        {items.map(item =>
{item}
)}
      
    )
  }
})

v-if : use ternary expression.

export
default
defineComponent({
  setup() {
let
isShow = ref<boolean>(true)
return
() => (
      <>
{isShow.value ?
我出来饿了
: ''}
{ isShow.value = !isShow.value }}>点我
)
  }
})

Note: JavaScript must be placed inside {} , and the return value should be a renderable element or an array of elements.

Slots

Default Slot

import
{ defineComponent, ref }
from
"vue"
export
default
defineComponent({
  setup(props, { slots }) {
let
text = ref<string>('我是默认插槽')
return
() => (
{text.value}
)
  }
})
let Child = (props: any, { slots }: any) => {
return
{slots.default()}
}

Named Slot

import
{ defineComponent, ref }
from
"vue"
export
default
defineComponent({
  setup(props, { slots }) {
let
text = ref<string>('我是默认插槽')
return
() => (
{{
          default: () => text.value,
          name1: () => '我是插槽1',
          name2: () => '我是插槽2'
        }}
)
  }
})
let Child = (props: any, { slots }: any) => {
return
{slots.default()}
{slots.name1()}
{slots.name2()}
}

Scoped Slot

export
default
defineComponent({
  setup(props, { slots }) {
let
text = ref<string>('我是默认插槽')
return
() => (
{{
          default: () => text.value,
          name1: () => '我是插槽1',
          name2: (parms: string) =>
{parms}
}}
)
  }
})
let Child = (props: any, { slots }: any) => {
let
parms: string = '我是参数'
return
{slots.default()}
{slots.name1()}
{slots.name2(parms)}
}

You can also pass elements to child components via props.

import
{ defineComponent, ref }
from
"vue"
export
default
defineComponent({
  setup(props, { slots }) {
let
text = ref<string>('我是默认插槽')
return
() => (
我是一
,
我是二
]} />
    )
  }
})
let Child = (props: any, { slots }: any) => {
return
{props?.childs[0]}
{props?.childs[1]}
}

Using Scoped CSS in Vue 3 TSX

In Vue 3, scoped CSS cannot be directly written in TSX files. Write TSX code inside the <script lang="tsx"> tag of a .vue single‑file component, and add the scoped attribute to the <style> tag.

<script lang="tsx">
import { defineComponent } from "vue"
export default defineComponent({
  setup() {
    return () => (
      <>
css scoped
)
  }
})
</script>
<style scoped>
.text {
  background: red;
}
</style>

Defining Props in Vue 3 + TSX

import
{ defineComponent, PropType }
from
"vue"
export
default
defineComponent({
  setup() {
return
() => (
      <>
我是父组件
)
  }
})
// child component
const
Text = defineComponent({
  props: {
    name: {
      type: String
as
PropType<string>,
      required: true
    }
  },
  setup(props) {
return
() => (
{props.name}
)
  }
})

Note: In TSX you can only define generic types like Object or String . For more specific types you need to use as PropType .

Simplifying Props Usage

Because defineComponent provides type inference, you may choose to define types manually with TypeScript.

Option 1: Without defineComponent, use TypeScript for type definitions.

Using TypeScript for type definitions works, but JSX cannot use this approach.

import
{ defineComponent }
from
"vue"
export
default
defineComponent({
  setup() {
return
() => (
      <>
我是父组件
)
  }
})
interface Props {
  name: string,
  age?: number
}
const
Text = (props: Props, ctx: any) => {
return
{props.name}
}

Option 2: Mixed Compilation

Reference: https://juejin.cn/post/7143053446365577253?searchId=202404031524149C416A3419D9B87C6B19

Option 3: Use Vue Macros to Build the Project

Reference: https://vue-macros.dev/zh-CN/guide/getting-started.html

Pros and Cons of JSX vs Template Syntax in Vue

JSX Syntax:

Advantages:

More flexible syntax: JSX allows JavaScript expressions inside the template, providing stronger expressive power and easier readability for developers familiar with JavaScript.

Component logic is more intuitive and maintainable: JSX keeps structure and logic together, enabling related components to be placed in the same file.

Better performance: JSX is compiled to pure JavaScript code, avoiding runtime template parsing.

Disadvantages:

Steeper learning curve: New developers, especially those unfamiliar with React or JSX, may need extra time to master it.

Mixing HTML with JavaScript: Some developers find embedding HTML in JavaScript less intuitive.

Differences from template syntax: TSX/JSX differs from Vue templates and does not support some template‑specific directives.

Template Syntax:

Advantages:

Easy to learn and start: It resembles traditional HTML, making it approachable for beginners.

HTML code is clear: The component structure is visually obvious.

Good editor support: Most editors provide syntax highlighting and auto‑completion for Vue templates.

Disadvantages:

Limited expressive ability: Templates cannot embed arbitrary JavaScript expressions.

Separation of component and logic: Some logic must be placed in the script section, leading to a clearer split between structure and behavior.

Overall, the choice between JSX and template syntax depends on personal preference, team technology stack, and project requirements. Vue 3 offers solid JSX support for developers comfortable with JavaScript, while template syntax remains a straightforward option for teams familiar with HTML.

Click the Follow button on the " Technical Dry Goods " public account to receive timely updates!

frontendcomponentVueTSXJSXScoped CSSslots
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.