[{"data":1,"prerenderedAt":1423},["ShallowReactive",2],{"blog-using-jsx-with-vue":3},{"id":4,"title":5,"author":6,"authorSlug":7,"body":8,"date":1414,"description":14,"extension":1415,"faq":7,"featured":1416,"image":1417,"meta":1418,"navigation":208,"path":1419,"readTime":7,"seo":1420,"stem":1421,"tags":7,"__hash__":1422},"blog\u002Fblog\u002Fusing-jsx-with-vue.md","Using JSX with Vue","Epicmax Team",null,{"type":9,"value":10,"toc":1410},"minimark",[11,15,26,38,41,46,49,58,364,378,382,394,416,422,569,575,583,586,752,758,905,911,1075,1085,1218,1228,1231,1239,1338,1406],[12,13,14],"p",{},"With Vue templates being the recommended way to build components by the framework standard, Vue also supports writing component markup using JSX or TSX with Typescript.",[12,16,17,18,25],{},"Despite common conception, JSX is not exclusive to React, although it was initially developed for and popularized by React as it’s way for writing markup within JavaScript. And even though Vue has it’s own alternative template syntax, ",[19,20,24],"a",{"href":21,"rel":22},"https:\u002F\u002Fvuejs.org\u002Fguide\u002Fextras\u002Frender-function.html#functional-components",[23],"nofollow","official docs"," acknowledge it’s limitations and the benefits that come from having the full programmatic power of JavaScript at your disposal when generation the markup and recognize the need for it for solving complex scenarios.",[12,27,28,29,37],{},"Teams maintaining large legacy Vue apps often benefit from professional ",[30,31,32],"strong",{},[19,33,36],{"href":34,"rel":35},"https:\u002F\u002Fepicmax.co\u002Fvue-3-migration",[23],"Vue.js migration services"," to adopt JSX strategically, ensuring maintainability and consistency across the codebase.",[12,39,40],{},"Let’s have a look on what are the options with using it in Vue.",[42,43,45],"h2",{"id":44},"how-jsx-is-possible-in-vue","How JSX is possible in Vue",[12,47,48],{},"Vue templates are syntactic sugar for you to right a more readable and DX-friendly way to create virtual DOM nodes (vnodes how Vue calls them) in an HTML-like markup.",[12,50,51,52,57],{},"You can check in the compiled templates that what it translates into under the hood are render functions with calls to function that creates vnodes that is h() function. You can read more on relationship between templates and render function in ",[19,53,56],{"href":54,"rel":55},"https:\u002F\u002Fvuejs.org\u002Fguide\u002Fextras\u002Frendering-mechanism.html#templates-vs-render-functions",[23],"Vue docs",".",[59,60,65],"pre",{"className":61,"code":62,"language":63,"meta":64,"style":64},"language-js shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const vnode = (\n  h(\n    'div',\n    {\n      id: 'foo',\n      class: 'bar',\n      \u002F\u002F here may go other props, possibly complex ones\n    },\n    [\n      \u002F* children *\u002F\n    ]\n  )\n);\n\nreturn (\n  \u003Cdiv class=\"container\">\n    \u003Cdiv class=\"header\">\n      Header content\n      {!isCompact && vnode}\n    \u003C\u002Fdiv>\n    \u003Cdiv class=\"footer\">\n      Footer content\n      {isCompact && vnode}\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n);\n","js","",[66,67,68,88,98,114,120,140,157,164,170,176,182,188,194,203,210,219,243,264,270,288,298,318,324,338,347,357],"code",{"__ignoreMap":64},[69,70,73,77,81,85],"span",{"class":71,"line":72},"line",1,[69,74,76],{"class":75},"spNyl","const",[69,78,80],{"class":79},"sTEyZ"," vnode ",[69,82,84],{"class":83},"sMK4o","=",[69,86,87],{"class":79}," (\n",[69,89,91,95],{"class":71,"line":90},2,[69,92,94],{"class":93},"s2Zo4","  h",[69,96,97],{"class":79},"(\n",[69,99,101,104,108,111],{"class":71,"line":100},3,[69,102,103],{"class":83},"    '",[69,105,107],{"class":106},"sfazB","div",[69,109,110],{"class":83},"'",[69,112,113],{"class":83},",\n",[69,115,117],{"class":71,"line":116},4,[69,118,119],{"class":83},"    {\n",[69,121,123,127,130,133,136,138],{"class":71,"line":122},5,[69,124,126],{"class":125},"swJcz","      id",[69,128,129],{"class":83},":",[69,131,132],{"class":83}," '",[69,134,135],{"class":106},"foo",[69,137,110],{"class":83},[69,139,113],{"class":83},[69,141,143,146,148,150,153,155],{"class":71,"line":142},6,[69,144,145],{"class":125},"      class",[69,147,129],{"class":83},[69,149,132],{"class":83},[69,151,152],{"class":106},"bar",[69,154,110],{"class":83},[69,156,113],{"class":83},[69,158,160],{"class":71,"line":159},7,[69,161,163],{"class":162},"sHwdD","      \u002F\u002F here may go other props, possibly complex ones\n",[69,165,167],{"class":71,"line":166},8,[69,168,169],{"class":83},"    },\n",[69,171,173],{"class":71,"line":172},9,[69,174,175],{"class":79},"    [\n",[69,177,179],{"class":71,"line":178},10,[69,180,181],{"class":162},"      \u002F* children *\u002F\n",[69,183,185],{"class":71,"line":184},11,[69,186,187],{"class":79},"    ]\n",[69,189,191],{"class":71,"line":190},12,[69,192,193],{"class":79},"  )\n",[69,195,197,200],{"class":71,"line":196},13,[69,198,199],{"class":79},")",[69,201,202],{"class":83},";\n",[69,204,206],{"class":71,"line":205},14,[69,207,209],{"emptyLinePlaceholder":208},true,"\n",[69,211,213,217],{"class":71,"line":212},15,[69,214,216],{"class":215},"s7zQu","return",[69,218,87],{"class":79},[69,220,222,225,227,230,232,235,238,240],{"class":71,"line":221},16,[69,223,224],{"class":83},"  \u003C",[69,226,107],{"class":125},[69,228,229],{"class":75}," class",[69,231,84],{"class":83},[69,233,234],{"class":83},"\"",[69,236,237],{"class":106},"container",[69,239,234],{"class":83},[69,241,242],{"class":83},">\n",[69,244,246,249,251,253,255,257,260,262],{"class":71,"line":245},17,[69,247,248],{"class":83},"    \u003C",[69,250,107],{"class":125},[69,252,229],{"class":75},[69,254,84],{"class":83},[69,256,234],{"class":83},[69,258,259],{"class":106},"header",[69,261,234],{"class":83},[69,263,242],{"class":83},[69,265,267],{"class":71,"line":266},18,[69,268,269],{"class":79},"      Header content\n",[69,271,273,276,279,282,285],{"class":71,"line":272},19,[69,274,275],{"class":83},"      {!",[69,277,278],{"class":79},"isCompact ",[69,280,281],{"class":83},"&&",[69,283,284],{"class":79}," vnode",[69,286,287],{"class":83},"}\n",[69,289,291,294,296],{"class":71,"line":290},20,[69,292,293],{"class":83},"    \u003C\u002F",[69,295,107],{"class":125},[69,297,242],{"class":83},[69,299,301,303,305,307,309,311,314,316],{"class":71,"line":300},21,[69,302,248],{"class":83},[69,304,107],{"class":125},[69,306,229],{"class":75},[69,308,84],{"class":83},[69,310,234],{"class":83},[69,312,313],{"class":106},"footer",[69,315,234],{"class":83},[69,317,242],{"class":83},[69,319,321],{"class":71,"line":320},22,[69,322,323],{"class":79},"      Footer content\n",[69,325,327,330,332,334,336],{"class":71,"line":326},23,[69,328,329],{"class":83},"      {",[69,331,278],{"class":79},[69,333,281],{"class":83},[69,335,284],{"class":79},[69,337,287],{"class":83},[69,339,341,343,345],{"class":71,"line":340},24,[69,342,293],{"class":83},[69,344,107],{"class":125},[69,346,242],{"class":83},[69,348,350,353,355],{"class":71,"line":349},25,[69,351,352],{"class":83},"  \u003C\u002F",[69,354,107],{"class":125},[69,356,242],{"class":83},[69,358,360,362],{"class":71,"line":359},26,[69,361,199],{"class":79},[69,363,202],{"class":83},[12,365,366,367,57,374,377],{},"Vue also provides APIs that allow us to skip the template compilation step and directly author render functions via exporting h() function that you can manually call. This is described in docs on ",[30,368,369],{},[19,370,373],{"href":371,"rel":372},"https:\u002F\u002Fvuejs.org\u002Fguide\u002Fextras\u002Frender-function.html#basic-usage",[23],"Render Functions & JSX",[375,376],"br",{},"\nJSX here comes into play here as an alternative syntactic sugar to define render functions, but contrary to Vue templates that are static JSX is written as part of your code directly so can be manipulated with it.",[42,379,381],{"id":380},"setup","Setup",[12,383,384,385,390,391,393],{},"create-vue and Vue CLI both have options for scaffolding projects with pre-configured JSX support. In order to manually enable an existing Vite-based Vue project with JSX you should perform the following configuration. (If you have different environment, see ",[19,386,389],{"href":387,"rel":388},"https:\u002F\u002Fvuejs.org\u002Fguide\u002Fextras\u002Frender-function.html#jsx-tsx",[23],"Vue docs on JSX\u002FTSX"," for configuring options)",[375,392],{},"\nInstall Vite plugin with command like:",[59,395,399],{"className":396,"code":397,"language":398,"meta":64,"style":64},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","npm install @vitejs\u002Fplugin-vue-jsx -D\n","bash",[66,400,401],{"__ignoreMap":64},[69,402,403,407,410,413],{"class":71,"line":72},[69,404,406],{"class":405},"sBMFI","npm",[69,408,409],{"class":106}," install",[69,411,412],{"class":106}," @vitejs\u002Fplugin-vue-jsx",[69,414,415],{"class":106}," -D\n",[12,417,418,419],{},"Next, add plugin to the ",[30,420,421],{},"vite.config.ts:",[59,423,425],{"className":61,"code":424,"language":63,"meta":64,"style":64},"\u002F\u002F vite.config.js\n\nimport { defineConfig } from 'vite'\nimport vue from '@vitejs\u002Fplugin-vue'\nimport vueJsx from '@vitejs\u002Fplugin-vue-jsx'\n\nexport default defineConfig({\n  plugins: [\n    vue(),\n    vueJsx(),\n  ],\n  \u002F\u002F other configurations\n  ...\n});\n",[66,426,427,432,436,461,478,494,498,514,524,534,543,550,555,560],{"__ignoreMap":64},[69,428,429],{"class":71,"line":72},[69,430,431],{"class":162},"\u002F\u002F vite.config.js\n",[69,433,434],{"class":71,"line":90},[69,435,209],{"emptyLinePlaceholder":208},[69,437,438,441,444,447,450,453,455,458],{"class":71,"line":100},[69,439,440],{"class":215},"import",[69,442,443],{"class":83}," {",[69,445,446],{"class":79}," defineConfig",[69,448,449],{"class":83}," }",[69,451,452],{"class":215}," from",[69,454,132],{"class":83},[69,456,457],{"class":106},"vite",[69,459,460],{"class":83},"'\n",[69,462,463,465,468,471,473,476],{"class":71,"line":116},[69,464,440],{"class":215},[69,466,467],{"class":79}," vue ",[69,469,470],{"class":215},"from",[69,472,132],{"class":83},[69,474,475],{"class":106},"@vitejs\u002Fplugin-vue",[69,477,460],{"class":83},[69,479,480,482,485,487,489,492],{"class":71,"line":122},[69,481,440],{"class":215},[69,483,484],{"class":79}," vueJsx ",[69,486,470],{"class":215},[69,488,132],{"class":83},[69,490,491],{"class":106},"@vitejs\u002Fplugin-vue-jsx",[69,493,460],{"class":83},[69,495,496],{"class":71,"line":142},[69,497,209],{"emptyLinePlaceholder":208},[69,499,500,503,506,508,511],{"class":71,"line":159},[69,501,502],{"class":215},"export",[69,504,505],{"class":215}," default",[69,507,446],{"class":93},[69,509,510],{"class":79},"(",[69,512,513],{"class":83},"{\n",[69,515,516,519,521],{"class":71,"line":166},[69,517,518],{"class":125},"  plugins",[69,520,129],{"class":83},[69,522,523],{"class":79}," [\n",[69,525,526,529,532],{"class":71,"line":172},[69,527,528],{"class":93},"    vue",[69,530,531],{"class":79},"()",[69,533,113],{"class":83},[69,535,536,539,541],{"class":71,"line":178},[69,537,538],{"class":93},"    vueJsx",[69,540,531],{"class":79},[69,542,113],{"class":83},[69,544,545,548],{"class":71,"line":184},[69,546,547],{"class":79},"  ]",[69,549,113],{"class":83},[69,551,552],{"class":71,"line":190},[69,553,554],{"class":162},"  \u002F\u002F other configurations\n",[69,556,557],{"class":71,"line":196},[69,558,559],{"class":83},"  ...\n",[69,561,562,565,567],{"class":71,"line":205},[69,563,564],{"class":83},"}",[69,566,199],{"class":79},[69,568,202],{"class":83},[12,570,571,572],{},"If you are using Typescript, make changes to ",[30,573,574],{},"tsconfig.json :",[59,576,581],{"className":577,"code":579,"language":580},[578],"language-text","\u002F\u002F tsconfig.json\n\n{\n  \"compilerOptions\": {\n    \"jsx\": \"preserve\",\n    \"jsxImportSource\": \"vue\",\n    \u002F\u002F other compiler options\n    ...\n  }\n}\n","text",[66,582,579],{"__ignoreMap":64},[12,584,585],{},"Vue docs are not so exhaustive in the section covering the topic and just tell that in Composition API a render function can be returned from setup() hook to be treated as component’s render output. Then they only showcase usage with h() function for explicitly creating vnodes:",[59,587,589],{"className":61,"code":588,"language":63,"meta":64,"style":64},"import { ref, h } from 'vue'\n\nexport default {\n  props: {\n    \u002F\u002F define props here\n    ...\n  },\n  setup(props) {\n    const count = ref(1)\n\n    \u002F\u002F return the render function\n    return () => h('div', props.msg + count.value)\n  }\n}\n",[66,590,591,617,621,630,639,644,649,654,669,691,695,700,743,748],{"__ignoreMap":64},[69,592,593,595,597,600,603,606,608,610,612,615],{"class":71,"line":72},[69,594,440],{"class":215},[69,596,443],{"class":83},[69,598,599],{"class":79}," ref",[69,601,602],{"class":83},",",[69,604,605],{"class":79}," h",[69,607,449],{"class":83},[69,609,452],{"class":215},[69,611,132],{"class":83},[69,613,614],{"class":106},"vue",[69,616,460],{"class":83},[69,618,619],{"class":71,"line":90},[69,620,209],{"emptyLinePlaceholder":208},[69,622,623,625,627],{"class":71,"line":100},[69,624,502],{"class":215},[69,626,505],{"class":215},[69,628,629],{"class":83}," {\n",[69,631,632,635,637],{"class":71,"line":116},[69,633,634],{"class":125},"  props",[69,636,129],{"class":83},[69,638,629],{"class":83},[69,640,641],{"class":71,"line":122},[69,642,643],{"class":162},"    \u002F\u002F define props here\n",[69,645,646],{"class":71,"line":142},[69,647,648],{"class":83},"    ...\n",[69,650,651],{"class":71,"line":159},[69,652,653],{"class":83},"  },\n",[69,655,656,659,661,665,667],{"class":71,"line":166},[69,657,658],{"class":125},"  setup",[69,660,510],{"class":83},[69,662,664],{"class":663},"sHdIc","props",[69,666,199],{"class":83},[69,668,629],{"class":83},[69,670,671,674,677,680,682,684,688],{"class":71,"line":172},[69,672,673],{"class":75},"    const",[69,675,676],{"class":79}," count",[69,678,679],{"class":83}," =",[69,681,599],{"class":93},[69,683,510],{"class":125},[69,685,687],{"class":686},"sbssI","1",[69,689,690],{"class":125},")\n",[69,692,693],{"class":71,"line":178},[69,694,209],{"emptyLinePlaceholder":208},[69,696,697],{"class":71,"line":184},[69,698,699],{"class":162},"    \u002F\u002F return the render function\n",[69,701,702,705,708,711,713,715,717,719,721,723,726,728,731,734,736,738,741],{"class":71,"line":190},[69,703,704],{"class":215},"    return",[69,706,707],{"class":83}," ()",[69,709,710],{"class":75}," =>",[69,712,605],{"class":93},[69,714,510],{"class":125},[69,716,110],{"class":83},[69,718,107],{"class":106},[69,720,110],{"class":83},[69,722,602],{"class":83},[69,724,725],{"class":79}," props",[69,727,57],{"class":83},[69,729,730],{"class":79},"msg",[69,732,733],{"class":83}," +",[69,735,676],{"class":79},[69,737,57],{"class":83},[69,739,740],{"class":79},"value",[69,742,690],{"class":125},[69,744,745],{"class":71,"line":196},[69,746,747],{"class":83},"  }\n",[69,749,750],{"class":71,"line":205},[69,751,287],{"class":83},[12,753,754,755,757],{},"The docs then imply that the render function can be written with JSX instead but don’t provide a complete example on this so let’s explore the options more closely.",[375,756],{},"\nThe equivalent of this with JSX would be:",[59,759,761],{"className":61,"code":760,"language":63,"meta":64,"style":64},"\u002F\u002F Component.jsx\n\nimport { ref } from \"vue\"\n\nexport default {\n  setup(props) {\n    const count = ref(1)\n\n    \u002F\u002F render function with JSX\n    return () => (\n      \u003Cdiv>\n        {props.msg + count.value}\n      \u003C\u002Fdiv>\n    )\n  }\n}\n",[66,762,763,768,772,792,796,804,816,832,836,841,851,860,883,892,897,901],{"__ignoreMap":64},[69,764,765],{"class":71,"line":72},[69,766,767],{"class":162},"\u002F\u002F Component.jsx\n",[69,769,770],{"class":71,"line":90},[69,771,209],{"emptyLinePlaceholder":208},[69,773,774,776,778,780,782,784,787,789],{"class":71,"line":100},[69,775,440],{"class":215},[69,777,443],{"class":83},[69,779,599],{"class":79},[69,781,449],{"class":83},[69,783,452],{"class":215},[69,785,786],{"class":83}," \"",[69,788,614],{"class":106},[69,790,791],{"class":83},"\"\n",[69,793,794],{"class":71,"line":116},[69,795,209],{"emptyLinePlaceholder":208},[69,797,798,800,802],{"class":71,"line":122},[69,799,502],{"class":215},[69,801,505],{"class":215},[69,803,629],{"class":83},[69,805,806,808,810,812,814],{"class":71,"line":142},[69,807,658],{"class":125},[69,809,510],{"class":83},[69,811,664],{"class":663},[69,813,199],{"class":83},[69,815,629],{"class":83},[69,817,818,820,822,824,826,828,830],{"class":71,"line":159},[69,819,673],{"class":75},[69,821,676],{"class":79},[69,823,679],{"class":83},[69,825,599],{"class":93},[69,827,510],{"class":125},[69,829,687],{"class":686},[69,831,690],{"class":125},[69,833,834],{"class":71,"line":166},[69,835,209],{"emptyLinePlaceholder":208},[69,837,838],{"class":71,"line":172},[69,839,840],{"class":162},"    \u002F\u002F render function with JSX\n",[69,842,843,845,847,849],{"class":71,"line":178},[69,844,704],{"class":215},[69,846,707],{"class":83},[69,848,710],{"class":75},[69,850,87],{"class":125},[69,852,853,856,858],{"class":71,"line":184},[69,854,855],{"class":83},"      \u003C",[69,857,107],{"class":125},[69,859,242],{"class":83},[69,861,862,865,867,869,872,875,877,879,881],{"class":71,"line":190},[69,863,864],{"class":83},"        {",[69,866,664],{"class":79},[69,868,57],{"class":83},[69,870,871],{"class":79},"msg ",[69,873,874],{"class":83},"+",[69,876,676],{"class":79},[69,878,57],{"class":83},[69,880,740],{"class":79},[69,882,287],{"class":83},[69,884,885,888,890],{"class":71,"line":196},[69,886,887],{"class":83},"      \u003C\u002F",[69,889,107],{"class":125},[69,891,242],{"class":83},[69,893,894],{"class":71,"line":205},[69,895,896],{"class":125},"    )\n",[69,898,899],{"class":71,"line":212},[69,900,747],{"class":83},[69,902,903],{"class":71,"line":221},[69,904,287],{"class":83},[12,906,907,908,910],{},"The file extension should be .jsx here to enable it.",[375,909],{},"\nOr the same in Typescript in .tsx and wrapped with defineComponent:",[59,912,914],{"className":61,"code":913,"language":63,"meta":64,"style":64},"\u002F\u002F Component.tsx\n\nimport { defineComponent, provide, inject, Ref, ref } from \"vue\"\n\nexport default defineComponent({\n  setup(props) {\n    const count = ref(1)\n\n    \u002F\u002F render function with JSX\n    return () => (\n      \u003Cdiv>\n        {props.msg + count.value}\n      \u003C\u002Fdiv>\n    )\n  }\n})\n",[66,915,916,921,925,963,967,979,991,1007,1011,1015,1025,1033,1053,1061,1065,1069],{"__ignoreMap":64},[69,917,918],{"class":71,"line":72},[69,919,920],{"class":162},"\u002F\u002F Component.tsx\n",[69,922,923],{"class":71,"line":90},[69,924,209],{"emptyLinePlaceholder":208},[69,926,927,929,931,934,936,939,941,944,946,949,951,953,955,957,959,961],{"class":71,"line":100},[69,928,440],{"class":215},[69,930,443],{"class":83},[69,932,933],{"class":79}," defineComponent",[69,935,602],{"class":83},[69,937,938],{"class":79}," provide",[69,940,602],{"class":83},[69,942,943],{"class":79}," inject",[69,945,602],{"class":83},[69,947,948],{"class":79}," Ref",[69,950,602],{"class":83},[69,952,599],{"class":79},[69,954,449],{"class":83},[69,956,452],{"class":215},[69,958,786],{"class":83},[69,960,614],{"class":106},[69,962,791],{"class":83},[69,964,965],{"class":71,"line":116},[69,966,209],{"emptyLinePlaceholder":208},[69,968,969,971,973,975,977],{"class":71,"line":122},[69,970,502],{"class":215},[69,972,505],{"class":215},[69,974,933],{"class":93},[69,976,510],{"class":79},[69,978,513],{"class":83},[69,980,981,983,985,987,989],{"class":71,"line":142},[69,982,658],{"class":125},[69,984,510],{"class":83},[69,986,664],{"class":663},[69,988,199],{"class":83},[69,990,629],{"class":83},[69,992,993,995,997,999,1001,1003,1005],{"class":71,"line":159},[69,994,673],{"class":75},[69,996,676],{"class":79},[69,998,679],{"class":83},[69,1000,599],{"class":93},[69,1002,510],{"class":125},[69,1004,687],{"class":686},[69,1006,690],{"class":125},[69,1008,1009],{"class":71,"line":166},[69,1010,209],{"emptyLinePlaceholder":208},[69,1012,1013],{"class":71,"line":172},[69,1014,840],{"class":162},[69,1016,1017,1019,1021,1023],{"class":71,"line":178},[69,1018,704],{"class":215},[69,1020,707],{"class":83},[69,1022,710],{"class":75},[69,1024,87],{"class":125},[69,1026,1027,1029,1031],{"class":71,"line":184},[69,1028,855],{"class":83},[69,1030,107],{"class":125},[69,1032,242],{"class":83},[69,1034,1035,1037,1039,1041,1043,1045,1047,1049,1051],{"class":71,"line":190},[69,1036,864],{"class":83},[69,1038,664],{"class":79},[69,1040,57],{"class":83},[69,1042,871],{"class":79},[69,1044,874],{"class":83},[69,1046,676],{"class":79},[69,1048,57],{"class":83},[69,1050,740],{"class":79},[69,1052,287],{"class":83},[69,1054,1055,1057,1059],{"class":71,"line":196},[69,1056,887],{"class":83},[69,1058,107],{"class":125},[69,1060,242],{"class":83},[69,1062,1063],{"class":71,"line":205},[69,1064,896],{"class":125},[69,1066,1067],{"class":71,"line":212},[69,1068,747],{"class":83},[69,1070,1071,1073],{"class":71,"line":221},[69,1072,564],{"class":83},[69,1074,690],{"class":79},[12,1076,1077,1078,1080,1081],{},"The former is what most articles show as examples and this may suggest that in order to use JSX in Vue one should ditch SFC and instead declare Options API style component mixing it up with setup() hook if you want to stick to the Composition API. But this is not the case.",[375,1079],{},"\nYou can use to JSX or TSX inside Vue SFC with specifying lang=\"jsx\" or lang=\"tsx\" on ",[1082,1083,1084],"script",{}," tag:",[59,1086,1088],{"className":61,"code":1087,"language":63,"meta":64,"style":64},"\u002F\u002F Component.vue\n\n\u003Cscript lang=\"tsx\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup(props) {\n    return () => (\n      \u003Cdiv>\n        Hello, World\n      \u003C\u002Fdiv>\n    )\n  }\n})\n\u003C\u002Fscript>\n",[66,1089,1090,1095,1099,1120,1136,1140,1147,1156,1166,1174,1184,1195,1199,1203,1209],{"__ignoreMap":64},[69,1091,1092],{"class":71,"line":72},[69,1093,1094],{"class":162},"\u002F\u002F Component.vue\n",[69,1096,1097],{"class":71,"line":90},[69,1098,209],{"emptyLinePlaceholder":208},[69,1100,1101,1104,1106,1109,1111,1113,1116,1118],{"class":71,"line":100},[69,1102,1103],{"class":83},"\u003C",[69,1105,1082],{"class":125},[69,1107,1108],{"class":75}," lang",[69,1110,84],{"class":83},[69,1112,234],{"class":83},[69,1114,1115],{"class":106},"tsx",[69,1117,234],{"class":83},[69,1119,242],{"class":83},[69,1121,1122,1125,1128,1131,1133],{"class":71,"line":116},[69,1123,1124],{"class":79},"import ",[69,1126,1127],{"class":83},"{",[69,1129,1130],{"class":79}," defineComponent ",[69,1132,564],{"class":83},[69,1134,1135],{"class":79}," from 'vue'\n",[69,1137,1138],{"class":71,"line":122},[69,1139,209],{"emptyLinePlaceholder":208},[69,1141,1142,1145],{"class":71,"line":142},[69,1143,1144],{"class":79},"export default defineComponent(",[69,1146,513],{"class":83},[69,1148,1149,1151,1154],{"class":71,"line":159},[69,1150,658],{"class":93},[69,1152,1153],{"class":79},"(props) ",[69,1155,513],{"class":83},[69,1157,1158,1160,1162,1164],{"class":71,"line":166},[69,1159,704],{"class":125},[69,1161,707],{"class":83},[69,1163,710],{"class":75},[69,1165,87],{"class":79},[69,1167,1168,1170,1172],{"class":71,"line":172},[69,1169,855],{"class":83},[69,1171,107],{"class":405},[69,1173,242],{"class":83},[69,1175,1176,1179,1181],{"class":71,"line":178},[69,1177,1178],{"class":405},"        Hello",[69,1180,602],{"class":83},[69,1182,1183],{"class":405}," World\n",[69,1185,1186,1188,1191,1193],{"class":71,"line":184},[69,1187,855],{"class":83},[69,1189,1190],{"class":79},"\u002F",[69,1192,107],{"class":405},[69,1194,242],{"class":83},[69,1196,1197],{"class":71,"line":190},[69,1198,896],{"class":79},[69,1200,1201],{"class":71,"line":196},[69,1202,747],{"class":83},[69,1204,1205,1207],{"class":71,"line":205},[69,1206,564],{"class":83},[69,1208,690],{"class":79},[69,1210,1211,1214,1216],{"class":71,"line":212},[69,1212,1213],{"class":83},"\u003C\u002F",[69,1215,1082],{"class":125},[69,1217,242],{"class":83},[12,1219,1220,1221,1224,1225],{},"You can even use JSX in ",[1082,1222,1223],{"setup":64}," with lang=\"tsx\" or lang=\"tsx\". In this scenario you can declare ** Functional Components","** in ",[1082,1226,1227],{"setup":64}," and use them in \u003Ctemplate> to render part of the markup**.**",[12,1229,1230],{},"Functional components are a lightweight form of component that must be pure functions and can’t have state or side-effect (pretty much like Function components in React before React hooks).",[12,1232,1233,1234,1238],{},"You can declare a single ",[19,1235,1237],{"href":21,"rel":1236},[23],"** Functional Components","** to produce your entire SFC markup like we did in the previous examples with component definition, you just need to call it not as a function but instantiate as a component:",[59,1240,1243],{"className":1241,"code":1242,"language":614,"meta":64,"style":64},"language-vue shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F Component.vue\n\n\u003Cscript lang=\"tsx\" setup>\nconst RenderComponent = () => (\n  \u003Cdiv>\n    Hello, World\n  \u003C\u002Fdiv>\n);\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CRenderComponent \u002F>\n\u003C\u002Ftemplate>\n",[66,1244,1245,1249,1253,1274,1279,1284,1289,1294,1299,1307,1311,1320,1330],{"__ignoreMap":64},[69,1246,1247],{"class":71,"line":72},[69,1248,1094],{"class":79},[69,1250,1251],{"class":71,"line":90},[69,1252,209],{"emptyLinePlaceholder":208},[69,1254,1255,1257,1259,1261,1263,1265,1267,1269,1272],{"class":71,"line":100},[69,1256,1103],{"class":83},[69,1258,1082],{"class":125},[69,1260,1108],{"class":75},[69,1262,84],{"class":83},[69,1264,234],{"class":83},[69,1266,1115],{"class":106},[69,1268,234],{"class":83},[69,1270,1271],{"class":75}," setup",[69,1273,242],{"class":83},[69,1275,1276],{"class":71,"line":116},[69,1277,1278],{"class":79},"const RenderComponent = () => (\n",[69,1280,1281],{"class":71,"line":122},[69,1282,1283],{"class":79},"  \u003Cdiv>\n",[69,1285,1286],{"class":71,"line":142},[69,1287,1288],{"class":79},"    Hello, World\n",[69,1290,1291],{"class":71,"line":159},[69,1292,1293],{"class":79},"  \u003C\u002Fdiv>\n",[69,1295,1296],{"class":71,"line":166},[69,1297,1298],{"class":79},");\n",[69,1300,1301,1303,1305],{"class":71,"line":172},[69,1302,1213],{"class":83},[69,1304,1082],{"class":125},[69,1306,242],{"class":83},[69,1308,1309],{"class":71,"line":178},[69,1310,209],{"emptyLinePlaceholder":208},[69,1312,1313,1315,1318],{"class":71,"line":184},[69,1314,1103],{"class":83},[69,1316,1317],{"class":125},"template",[69,1319,242],{"class":83},[69,1321,1322,1324,1327],{"class":71,"line":190},[69,1323,224],{"class":83},[69,1325,1326],{"class":125},"RenderComponent",[69,1328,1329],{"class":83}," \u002F>\n",[69,1331,1332,1334,1336],{"class":71,"line":196},[69,1333,1213],{"class":83},[69,1335,1317],{"class":125},[69,1337,242],{"class":83},[12,1339,1340,1341],{},"But perhaps the most potent is that you can still use ",[1317,1342,1343,1344,1348,1349],{}," for most of your template like you normally would in Vue and occasionally embed a ",[19,1345,1347],{"href":21,"rel":1346},[23],"** Functional Component","** to produce some parts of the markup that can’t be easily expressed with the template syntax.",[12,1350,1351,1352,1357,1358,1360,1361,1364,1365],{},"One of the notable limitations is inability to define a template part and reuse it across template, for example when some block needs to appear in different places in the markup depending on some condition (although there is now an alternative pure-template solution for this problem that is explored in ",[19,1353,1356],{"href":1354,"rel":1355},"https:\u002F\u002Fwww.notion.so\u002FFixing-Vue-SFC-templates-for-React-developers-e449f064f64a4b6c9d3d303e107a71dc?pvs=21",[23],"another article",").",[375,1359],{},"\nThis part can be extracted into a ",[19,1362,1347],{"href":21,"rel":1363},[23],"** and reused across ",[1317,1366,1367,1368,1375,1384,1390,1395,1401],{}," :\n",[59,1369,1373],{"className":1370,"code":1372,"language":614,"meta":64},[1371],"language-vue","\u002F\u002F Component.vue\n\n\u003Cscript lang=\"tsx\" setup>\nimport { ref } from 'vue';\n\nconst ReusedPart = () => (\n  \u003Cdiv>\n    Hello, World\n  \u003C\u002Fdiv>\n);\n\nconst someCondition = ref(true);\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003CReusedPart v-if=\"someCondition\" \u002F>\n  \u003C\u002Fdiv>\n  \u003Cdiv>\n    \u003CReusedPart v-if=\"!someCondition\" \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[66,1374,1372],{"__ignoreMap":64},[12,1376,1377,1383],{},[30,1378,1379],{},[19,1380,1382],{"href":21,"rel":1381},[23],"Functional Component"," can be passed props, just like you would pass them to normal components:",[59,1385,1388],{"className":1386,"code":1387,"language":614,"meta":64},[1371],"\u002F\u002F Component.vue\n\n\u003Cscript lang=\"tsx\" setup>\ninterface Props {\n  label: string;\n}\n\nconst SubComponentA = (props: Props) => (\n  \u003Cdiv>\n    \u003Clabel>{props.label}\u003C\u002Flabel>\n    \u003Cinput type=\"number\" \u002F>\n  \u003C\u002Fdiv>\n);\n\nconst SubComponentB = (props: Props) => (\n  \u003Cdiv>\n    \u003Clabel>{props.label}\u003C\u002Flabel>\n    \u003Ctextarea \u002F>\n  \u003C\u002Fdiv>\n);\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CSubComponentA label=\"Label 1\" \u002F>\n  \u003CSubComponentB label=\"Label 2\" \u002F>\n  \u003CSubComponentA label=\"Label 3\" \u002F>\n  \u003CSubComponentB label=\"Label 4\" \u002F>\n\u003C\u002Ftemplate>\n",[66,1389,1387],{"__ignoreMap":64},[12,1391,1392],{},[30,1393,1394],{},"Hope that this was a usefull tour on how to incorporate JSX in your Vue app to help you write your templates more easily.",[12,1396,1397],{},[1398,1399,1400],"em",{},"Autor: Alexandra Petrova, Lead Frontend developer",[1402,1403],"blog-button",{"label":1404,"to":1405},"Talk to an engineer","https:\u002F\u002Fcalendar.app.google\u002FXwRzASZitZRSVLxq6",[1407,1408,1409],"style",{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":64,"searchDepth":100,"depth":100,"links":1411},[1412,1413],{"id":44,"depth":90,"text":45},{"id":380,"depth":90,"text":381},"2023-03-27","md",false,"\u002Fimages\u002Fblog\u002Fusing-jsx-with-vue\u002Fcard.png",{},"\u002Fblog\u002Fusing-jsx-with-vue",{"title":5,"description":14},"blog\u002Fusing-jsx-with-vue","3CbtAbKE3WYQN1Rno-bh8ZLGFzCRILTCvXCdNM6PXZU",1784559991785]