[{"data":1,"prerenderedAt":2991},["ShallowReactive",2],{"en-article-\u002Fen\u002Fblog\u002Fwhat-are-directives-in-vue-and-how-to-implement-them":3,"en-related-posts-\u002Fen\u002Fblog\u002Fwhat-are-directives-in-vue-and-how-to-implement-them":2884},{"id":4,"title":5,"articleCover":6,"articleCoverEmbed":7,"articleCoverEmbedUploadDate":7,"articleCoverHeight":8,"articleCoverWidth":9,"authorId":10,"body":11,"categoriesIds":2869,"description":2871,"enAlternateSlug":2872,"extension":2873,"meta":2874,"navigation":162,"path":2875,"ptBrAlternateSlug":2876,"publishedAt":2877,"seo":2878,"sitemap":2879,"stem":2881,"updatedAt":2880,"wordCount":2882,"__hash__":2883},"blogEn\u002Fen\u002Fblog\u002Fwhat-are-directives-in-vue-and-how-to-implement-them.md","Vue 3 Directives: Built-in and Custom","\u002Fimages\u002Fen\u002Fblog\u002Fvue\u002Fwhat-are-directives-in-vue-and-how-to-implement-them.webp",null,772,1372,"eduardo-goncalves-souza",{"type":12,"value":13,"toc":2834},"minimark",[14,31,38,43,46,55,59,75,275,302,306,311,317,436,440,445,578,591,595,600,769,773,782,980,987,991,1003,1175,1179,1188,1232,1236,1250,1259,1263,1266,1301,1305,1316,1325,1342,1346,1349,1353,1370,1470,1477,1481,1487,1575,1698,1702,1705,1748,1800,1804,1811,1949,1972,1976,1987,2288,2304,2308,2311,2314,2318,2333,2442,2460,2475,2547,2596,2600,2603,2651,2667,2671,2710,2714,2718,2724,2728,2745,2749,2752,2756,2768,2772,2775,2779,2791,2795,2806,2830],[15,16,17,18,22,23,26,27,30],"p",{},"Directives are special template attributes, always prefixed with ",[19,20,21],"code",{},"v-",", that connect your HTML to the state and behavior of your application. This article covers the built-in Vue 3 directives, the syntax with arguments and modifiers, how to choose between ",[19,24,25],{},"v-if"," and ",[19,28,29],{},"v-show",", and how to build your own directive, including in Nuxt 4, where you also have to handle server-side rendering.",[15,32,33,34,37],{},"The examples use Vue 3.5 with ",[19,35,36],{},"\u003Cscript setup>",".",[39,40,42],"h2",{"id":41},"what-are-directives-in-vue","What Are Directives in Vue?",[15,44,45],{},"A directive takes a JavaScript expression as its value and applies reactive behavior to the element it sits on. When the value changes, Vue updates the element. Directives control attributes, events, list rendering and which elements appear on screen.",[15,47,48,49,26,51,54],{},"There are two groups. Built-in directives, like ",[19,50,25],{},[19,52,53],{},"v-for",", ship with Vue. Custom directives are the ones you write yourself for cases where you need to work directly with a DOM element.",[39,56,58],{"id":57},"how-does-the-directive-syntax-work","How Does the Directive Syntax Work?",[15,60,61,62,65,66,26,69,65,72,64],{},"A directive has up to four parts: the name, an optional argument after a colon, optional modifiers separated by dots, and the value. The first two lines below are equivalent, because ",[19,63,64],{},":"," is shorthand for ",[19,67,68],{},"v-bind:",[19,70,71],{},"@",[19,73,74],{},"v-on:",[76,77,82],"pre",{"className":78,"code":79,"language":80,"meta":81,"style":81},"language-vue shiki shiki-themes dracula","\u003Ctemplate>\n  \u003Ca v-bind:href=\"url\">Visit our website\u003C\u002Fa>\n  \u003Ca :href=\"url\">Visit our website\u003C\u002Fa>\n\n  \u003Cbutton @click=\"save\">Save\u003C\u002Fbutton>\n\n  \u003C!-- dynamic argument: the attribute name comes from a variable -->\n  \u003Ca :[attribute]=\"url\">Visit our website\u003C\u002Fa>\n\n  \u003C!-- modifier: calls event.preventDefault() on submit -->\n  \u003Cform @submit.prevent=\"submit\">...\u003C\u002Fform>\n\u003C\u002Ftemplate>\n","vue","",[19,83,84,100,133,157,164,191,196,203,227,232,238,265],{"__ignoreMap":81},[85,86,89,93,97],"span",{"class":87,"line":88},"line",1,[85,90,92],{"class":91},"sCdxs","\u003C",[85,94,96],{"class":95},"s0Tla","template",[85,98,99],{"class":91},">\n",[85,101,103,106,109,113,116,120,124,126,129,131],{"class":87,"line":102},2,[85,104,105],{"class":91},"  \u003C",[85,107,108],{"class":95},"a",[85,110,112],{"class":111},"sY_PY"," v-bind:href",[85,114,115],{"class":95},"=",[85,117,119],{"class":118},"seVfx","\"",[85,121,123],{"class":122},"s-mGx","url",[85,125,119],{"class":118},[85,127,128],{"class":91},">Visit our website\u003C\u002F",[85,130,108],{"class":95},[85,132,99],{"class":91},[85,134,136,138,140,143,145,147,149,151,153,155],{"class":87,"line":135},3,[85,137,105],{"class":91},[85,139,108],{"class":95},[85,141,142],{"class":111}," :href",[85,144,115],{"class":95},[85,146,119],{"class":118},[85,148,123],{"class":122},[85,150,119],{"class":118},[85,152,128],{"class":91},[85,154,108],{"class":95},[85,156,99],{"class":91},[85,158,160],{"class":87,"line":159},4,[85,161,163],{"emptyLinePlaceholder":162},true,"\n",[85,165,167,169,172,175,177,179,182,184,187,189],{"class":87,"line":166},5,[85,168,105],{"class":91},[85,170,171],{"class":95},"button",[85,173,174],{"class":111}," @click",[85,176,115],{"class":95},[85,178,119],{"class":118},[85,180,181],{"class":122},"save",[85,183,119],{"class":118},[85,185,186],{"class":91},">Save\u003C\u002F",[85,188,171],{"class":95},[85,190,99],{"class":91},[85,192,194],{"class":87,"line":193},6,[85,195,163],{"emptyLinePlaceholder":162},[85,197,199],{"class":87,"line":198},7,[85,200,202],{"class":201},"shSDL","  \u003C!-- dynamic argument: the attribute name comes from a variable -->\n",[85,204,206,208,210,213,215,217,219,221,223,225],{"class":87,"line":205},8,[85,207,105],{"class":91},[85,209,108],{"class":95},[85,211,212],{"class":111}," :[attribute]",[85,214,115],{"class":95},[85,216,119],{"class":118},[85,218,123],{"class":122},[85,220,119],{"class":118},[85,222,128],{"class":91},[85,224,108],{"class":95},[85,226,99],{"class":91},[85,228,230],{"class":87,"line":229},9,[85,231,163],{"emptyLinePlaceholder":162},[85,233,235],{"class":87,"line":234},10,[85,236,237],{"class":201},"  \u003C!-- modifier: calls event.preventDefault() on submit -->\n",[85,239,241,243,246,249,251,253,256,258,261,263],{"class":87,"line":240},11,[85,242,105],{"class":91},[85,244,245],{"class":95},"form",[85,247,248],{"class":111}," @submit.prevent",[85,250,115],{"class":95},[85,252,119],{"class":118},[85,254,255],{"class":122},"submit",[85,257,119],{"class":118},[85,259,260],{"class":91},">...\u003C\u002F",[85,262,245],{"class":95},[85,264,99],{"class":91},[85,266,268,271,273],{"class":87,"line":267},12,[85,269,270],{"class":91},"\u003C\u002F",[85,272,96],{"class":95},[85,274,99],{"class":91},[15,276,277,278,26,281,284,285,288,289,292,293,26,296,284,299,37],{},"In Vue projects, the short form is the most common. Modifiers change how a directive behaves, and each directive has its own. ",[19,279,280],{},".prevent",[19,282,283],{},".stop"," apply to ",[19,286,287],{},"v-on",", while ",[19,290,291],{},".lazy",", ",[19,294,295],{},".number",[19,297,298],{},".trim",[19,300,301],{},"v-model",[39,303,305],{"id":304},"what-are-the-main-built-in-directives","What Are the Main Built-in Directives?",[307,308,310],"h3",{"id":309},"v-bind-dynamic-attributes","v-bind: Dynamic Attributes",[15,312,313,316],{},[19,314,315],{},"v-bind"," links the value of a variable to an element attribute. If the variable changes, the attribute changes with it:",[76,318,320],{"className":78,"code":319,"language":80,"meta":81,"style":81},"\u003Ctemplate>\n  \u003Ca :href=\"url\">Visit our website\u003C\u002Fa>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport { ref } from \"vue\";\n\nconst url = ref(\"https:\u002F\u002Fcodigoaoponto.com\u002F\");\n\u003C\u002Fscript>\n",[19,321,322,330,352,360,364,376,397,401,428],{"__ignoreMap":81},[85,323,324,326,328],{"class":87,"line":88},[85,325,92],{"class":91},[85,327,96],{"class":95},[85,329,99],{"class":91},[85,331,332,334,336,338,340,342,344,346,348,350],{"class":87,"line":102},[85,333,105],{"class":91},[85,335,108],{"class":95},[85,337,142],{"class":111},[85,339,115],{"class":95},[85,341,119],{"class":118},[85,343,123],{"class":122},[85,345,119],{"class":118},[85,347,128],{"class":91},[85,349,108],{"class":95},[85,351,99],{"class":91},[85,353,354,356,358],{"class":87,"line":135},[85,355,270],{"class":91},[85,357,96],{"class":95},[85,359,99],{"class":91},[85,361,362],{"class":87,"line":159},[85,363,163],{"emptyLinePlaceholder":162},[85,365,366,368,371,374],{"class":87,"line":166},[85,367,92],{"class":91},[85,369,370],{"class":95},"script",[85,372,373],{"class":111}," setup",[85,375,99],{"class":91},[85,377,378,381,384,387,390,392,394],{"class":87,"line":193},[85,379,380],{"class":95},"import",[85,382,383],{"class":91}," { ref } ",[85,385,386],{"class":95},"from",[85,388,389],{"class":118}," \"",[85,391,80],{"class":122},[85,393,119],{"class":118},[85,395,396],{"class":91},";\n",[85,398,399],{"class":87,"line":198},[85,400,163],{"emptyLinePlaceholder":162},[85,402,403,406,409,411,415,418,420,423,425],{"class":87,"line":205},[85,404,405],{"class":95},"const",[85,407,408],{"class":91}," url ",[85,410,115],{"class":95},[85,412,414],{"class":413},"sAOxA"," ref",[85,416,417],{"class":91},"(",[85,419,119],{"class":118},[85,421,422],{"class":122},"https:\u002F\u002Fcodigoaoponto.com\u002F",[85,424,119],{"class":118},[85,426,427],{"class":91},");\n",[85,429,430,432,434],{"class":87,"line":229},[85,431,270],{"class":91},[85,433,370],{"class":95},[85,435,99],{"class":91},[307,437,439],{"id":438},"v-model-two-way-binding","v-model: Two-Way Binding",[15,441,442,444],{},[19,443,301],{}," keeps a form field and a variable in sync in both directions. Typing in the field updates the variable, and changing the variable updates the field:",[76,446,448],{"className":78,"code":447,"language":80,"meta":81,"style":81},"\u003Ctemplate>\n  \u003Cinput v-model=\"name\" type=\"text\" \u002F>\n  \u003Cdiv>Hello! My name is {{ name }}\u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport { ref } from \"vue\";\n\nconst name = ref(\"Test\");\n\u003C\u002Fscript>\n",[19,449,450,458,492,506,514,518,528,544,548,570],{"__ignoreMap":81},[85,451,452,454,456],{"class":87,"line":88},[85,453,92],{"class":91},[85,455,96],{"class":95},[85,457,99],{"class":91},[85,459,460,462,465,468,470,472,475,477,480,482,484,487,489],{"class":87,"line":102},[85,461,105],{"class":91},[85,463,464],{"class":95},"input",[85,466,467],{"class":111}," v-model",[85,469,115],{"class":95},[85,471,119],{"class":118},[85,473,474],{"class":122},"name",[85,476,119],{"class":118},[85,478,479],{"class":111}," type",[85,481,115],{"class":95},[85,483,119],{"class":118},[85,485,486],{"class":122},"text",[85,488,119],{"class":118},[85,490,491],{"class":91}," \u002F>\n",[85,493,494,496,499,502,504],{"class":87,"line":135},[85,495,105],{"class":91},[85,497,498],{"class":95},"div",[85,500,501],{"class":91},">Hello! My name is {{ name }}\u003C\u002F",[85,503,498],{"class":95},[85,505,99],{"class":91},[85,507,508,510,512],{"class":87,"line":159},[85,509,270],{"class":91},[85,511,96],{"class":95},[85,513,99],{"class":91},[85,515,516],{"class":87,"line":166},[85,517,163],{"emptyLinePlaceholder":162},[85,519,520,522,524,526],{"class":87,"line":193},[85,521,92],{"class":91},[85,523,370],{"class":95},[85,525,373],{"class":111},[85,527,99],{"class":91},[85,529,530,532,534,536,538,540,542],{"class":87,"line":198},[85,531,380],{"class":95},[85,533,383],{"class":91},[85,535,386],{"class":95},[85,537,389],{"class":118},[85,539,80],{"class":122},[85,541,119],{"class":118},[85,543,396],{"class":91},[85,545,546],{"class":87,"line":205},[85,547,163],{"emptyLinePlaceholder":162},[85,549,550,552,555,557,559,561,563,566,568],{"class":87,"line":229},[85,551,405],{"class":95},[85,553,554],{"class":91}," name ",[85,556,115],{"class":95},[85,558,414],{"class":413},[85,560,417],{"class":91},[85,562,119],{"class":118},[85,564,565],{"class":122},"Test",[85,567,119],{"class":118},[85,569,427],{"class":91},[85,571,572,574,576],{"class":87,"line":234},[85,573,270],{"class":91},[85,575,370],{"class":95},[85,577,99],{"class":91},[15,579,580,581,583,584,586,587,590],{},"On components, ",[19,582,301],{}," relies on a matching prop and event. In Vue 3 you can have more than one ",[19,585,301],{}," on the same component, each with its own name. Since Vue 3.4, the ",[19,588,589],{},"defineModel"," macro creates that prop and event pair for you.",[307,592,594],{"id":593},"v-on-events","v-on: Events",[15,596,597,599],{},[19,598,287],{}," connects a browser event to a function:",[76,601,603],{"className":78,"code":602,"language":80,"meta":81,"style":81},"\u003Ctemplate>\n  \u003Cinput v-model=\"name\" type=\"text\" \u002F>\n  \u003Cbutton @click=\"reset\">Reset\u003C\u002Fbutton>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport { ref } from \"vue\";\n\nconst name = ref(\"Test\");\n\nfunction reset() {\n  name.value = \"\";\n}\n\u003C\u002Fscript>\n",[19,604,605,613,641,665,673,677,687,703,707,727,731,742,754,760],{"__ignoreMap":81},[85,606,607,609,611],{"class":87,"line":88},[85,608,92],{"class":91},[85,610,96],{"class":95},[85,612,99],{"class":91},[85,614,615,617,619,621,623,625,627,629,631,633,635,637,639],{"class":87,"line":102},[85,616,105],{"class":91},[85,618,464],{"class":95},[85,620,467],{"class":111},[85,622,115],{"class":95},[85,624,119],{"class":118},[85,626,474],{"class":122},[85,628,119],{"class":118},[85,630,479],{"class":111},[85,632,115],{"class":95},[85,634,119],{"class":118},[85,636,486],{"class":122},[85,638,119],{"class":118},[85,640,491],{"class":91},[85,642,643,645,647,649,651,653,656,658,661,663],{"class":87,"line":135},[85,644,105],{"class":91},[85,646,171],{"class":95},[85,648,174],{"class":111},[85,650,115],{"class":95},[85,652,119],{"class":118},[85,654,655],{"class":122},"reset",[85,657,119],{"class":118},[85,659,660],{"class":91},">Reset\u003C\u002F",[85,662,171],{"class":95},[85,664,99],{"class":91},[85,666,667,669,671],{"class":87,"line":159},[85,668,270],{"class":91},[85,670,96],{"class":95},[85,672,99],{"class":91},[85,674,675],{"class":87,"line":166},[85,676,163],{"emptyLinePlaceholder":162},[85,678,679,681,683,685],{"class":87,"line":193},[85,680,92],{"class":91},[85,682,370],{"class":95},[85,684,373],{"class":111},[85,686,99],{"class":91},[85,688,689,691,693,695,697,699,701],{"class":87,"line":198},[85,690,380],{"class":95},[85,692,383],{"class":91},[85,694,386],{"class":95},[85,696,389],{"class":118},[85,698,80],{"class":122},[85,700,119],{"class":118},[85,702,396],{"class":91},[85,704,705],{"class":87,"line":205},[85,706,163],{"emptyLinePlaceholder":162},[85,708,709,711,713,715,717,719,721,723,725],{"class":87,"line":229},[85,710,405],{"class":95},[85,712,554],{"class":91},[85,714,115],{"class":95},[85,716,414],{"class":413},[85,718,417],{"class":91},[85,720,119],{"class":118},[85,722,565],{"class":122},[85,724,119],{"class":118},[85,726,427],{"class":91},[85,728,729],{"class":87,"line":234},[85,730,163],{"emptyLinePlaceholder":162},[85,732,733,736,739],{"class":87,"line":240},[85,734,735],{"class":95},"function",[85,737,738],{"class":413}," reset",[85,740,741],{"class":91},"() {\n",[85,743,744,747,749,752],{"class":87,"line":267},[85,745,746],{"class":91},"  name.value ",[85,748,115],{"class":95},[85,750,751],{"class":118}," \"\"",[85,753,396],{"class":91},[85,755,757],{"class":87,"line":756},13,[85,758,759],{"class":91},"}\n",[85,761,763,765,767],{"class":87,"line":762},14,[85,764,270],{"class":91},[85,766,370],{"class":95},[85,768,99],{"class":91},[307,770,772],{"id":771},"v-for-lists-and-the-key","v-for: Lists and the Key",[15,774,775,777,778,781],{},[19,776,53],{}," creates one element for each item in an array or object. It needs a ",[19,779,780],{},":key"," with a unique, stable value for each item, so Vue knows which element matches which piece of data:",[76,783,785],{"className":78,"code":784,"language":80,"meta":81,"style":81},"\u003Ctemplate>\n  \u003Cul>\n    \u003Cli v-for=\"task in tasks\" :key=\"task.id\">\n      {{ task.title }}\n    \u003C\u002Fli>\n  \u003C\u002Ful>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nconst tasks = [\n  { id: 101, title: \"Review the documentation\" },\n  { id: 102, title: \"Update the dependencies\" },\n  { id: 103, title: \"Publish the article\" }\n];\n\u003C\u002Fscript>\n",[19,786,787,795,804,838,843,852,861,869,873,883,895,921,943,966,971],{"__ignoreMap":81},[85,788,789,791,793],{"class":87,"line":88},[85,790,92],{"class":91},[85,792,96],{"class":95},[85,794,99],{"class":91},[85,796,797,799,802],{"class":87,"line":102},[85,798,105],{"class":91},[85,800,801],{"class":95},"ul",[85,803,99],{"class":91},[85,805,806,809,812,815,817,819,822,824,827,829,831,834,836],{"class":87,"line":135},[85,807,808],{"class":91},"    \u003C",[85,810,811],{"class":95},"li",[85,813,814],{"class":111}," v-for",[85,816,115],{"class":95},[85,818,119],{"class":118},[85,820,821],{"class":122},"task in tasks",[85,823,119],{"class":118},[85,825,826],{"class":111}," :key",[85,828,115],{"class":95},[85,830,119],{"class":118},[85,832,833],{"class":122},"task.id",[85,835,119],{"class":118},[85,837,99],{"class":91},[85,839,840],{"class":87,"line":159},[85,841,842],{"class":91},"      {{ task.title }}\n",[85,844,845,848,850],{"class":87,"line":166},[85,846,847],{"class":91},"    \u003C\u002F",[85,849,811],{"class":95},[85,851,99],{"class":91},[85,853,854,857,859],{"class":87,"line":193},[85,855,856],{"class":91},"  \u003C\u002F",[85,858,801],{"class":95},[85,860,99],{"class":91},[85,862,863,865,867],{"class":87,"line":198},[85,864,270],{"class":91},[85,866,96],{"class":95},[85,868,99],{"class":91},[85,870,871],{"class":87,"line":205},[85,872,163],{"emptyLinePlaceholder":162},[85,874,875,877,879,881],{"class":87,"line":229},[85,876,92],{"class":91},[85,878,370],{"class":95},[85,880,373],{"class":111},[85,882,99],{"class":91},[85,884,885,887,890,892],{"class":87,"line":234},[85,886,405],{"class":95},[85,888,889],{"class":91}," tasks ",[85,891,115],{"class":95},[85,893,894],{"class":91}," [\n",[85,896,897,900,902,906,909,911,913,916,918],{"class":87,"line":240},[85,898,899],{"class":91},"  { id",[85,901,64],{"class":95},[85,903,905],{"class":904},"sIQBb"," 101",[85,907,908],{"class":91},", title",[85,910,64],{"class":95},[85,912,389],{"class":118},[85,914,915],{"class":122},"Review the documentation",[85,917,119],{"class":118},[85,919,920],{"class":91}," },\n",[85,922,923,925,927,930,932,934,936,939,941],{"class":87,"line":267},[85,924,899],{"class":91},[85,926,64],{"class":95},[85,928,929],{"class":904}," 102",[85,931,908],{"class":91},[85,933,64],{"class":95},[85,935,389],{"class":118},[85,937,938],{"class":122},"Update the dependencies",[85,940,119],{"class":118},[85,942,920],{"class":91},[85,944,945,947,949,952,954,956,958,961,963],{"class":87,"line":756},[85,946,899],{"class":91},[85,948,64],{"class":95},[85,950,951],{"class":904}," 103",[85,953,908],{"class":91},[85,955,64],{"class":95},[85,957,389],{"class":118},[85,959,960],{"class":122},"Publish the article",[85,962,119],{"class":118},[85,964,965],{"class":91}," }\n",[85,967,968],{"class":87,"line":762},[85,969,970],{"class":91},"];\n",[85,972,974,976,978],{"class":87,"line":973},15,[85,975,270],{"class":91},[85,977,370],{"class":95},[85,979,99],{"class":91},[15,981,982,983,986],{},"The array index only works as a ",[19,984,985],{},"key"," in static lists. If the list can be reordered, filtered, or gain and lose items, the index makes Vue reuse the wrong element. The problem shows up mostly when each row has a text field, a component or an animation with its own state.",[307,988,990],{"id":989},"v-if-v-else-if-and-v-else-conditional-rendering","v-if, v-else-if and v-else: Conditional Rendering",[15,992,993,995,996,26,999,1002],{},[19,994,25],{}," includes the element only when the condition is true. ",[19,997,998],{},"v-else-if",[19,1000,1001],{},"v-else"," chain the alternatives:",[76,1004,1006],{"className":78,"code":1005,"language":80,"meta":81,"style":81},"\u003Ctemplate>\n  \u003Cinput v-model=\"name\" type=\"text\" \u002F>\n  \u003Cdiv v-if=\"name.length > 10\">Your name is too long!\u003C\u002Fdiv>\n  \u003Cdiv v-else-if=\"name\">Hello! My name is {{ name }}\u003C\u002Fdiv>\n  \u003Cdiv v-else>Please enter your name.\u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport { ref } from \"vue\";\n\nconst name = ref(\"\");\n\u003C\u002Fscript>\n",[19,1007,1008,1016,1044,1069,1092,1108,1116,1120,1130,1146,1150,1167],{"__ignoreMap":81},[85,1009,1010,1012,1014],{"class":87,"line":88},[85,1011,92],{"class":91},[85,1013,96],{"class":95},[85,1015,99],{"class":91},[85,1017,1018,1020,1022,1024,1026,1028,1030,1032,1034,1036,1038,1040,1042],{"class":87,"line":102},[85,1019,105],{"class":91},[85,1021,464],{"class":95},[85,1023,467],{"class":111},[85,1025,115],{"class":95},[85,1027,119],{"class":118},[85,1029,474],{"class":122},[85,1031,119],{"class":118},[85,1033,479],{"class":111},[85,1035,115],{"class":95},[85,1037,119],{"class":118},[85,1039,486],{"class":122},[85,1041,119],{"class":118},[85,1043,491],{"class":91},[85,1045,1046,1048,1050,1053,1055,1057,1060,1062,1065,1067],{"class":87,"line":135},[85,1047,105],{"class":91},[85,1049,498],{"class":95},[85,1051,1052],{"class":111}," v-if",[85,1054,115],{"class":95},[85,1056,119],{"class":118},[85,1058,1059],{"class":122},"name.length > 10",[85,1061,119],{"class":118},[85,1063,1064],{"class":91},">Your name is too long!\u003C\u002F",[85,1066,498],{"class":95},[85,1068,99],{"class":91},[85,1070,1071,1073,1075,1078,1080,1082,1084,1086,1088,1090],{"class":87,"line":159},[85,1072,105],{"class":91},[85,1074,498],{"class":95},[85,1076,1077],{"class":111}," v-else-if",[85,1079,115],{"class":95},[85,1081,119],{"class":118},[85,1083,474],{"class":122},[85,1085,119],{"class":118},[85,1087,501],{"class":91},[85,1089,498],{"class":95},[85,1091,99],{"class":91},[85,1093,1094,1096,1098,1101,1104,1106],{"class":87,"line":166},[85,1095,105],{"class":91},[85,1097,498],{"class":95},[85,1099,1100],{"class":111}," v-else",[85,1102,1103],{"class":91},">Please enter your name.\u003C\u002F",[85,1105,498],{"class":95},[85,1107,99],{"class":91},[85,1109,1110,1112,1114],{"class":87,"line":193},[85,1111,270],{"class":91},[85,1113,96],{"class":95},[85,1115,99],{"class":91},[85,1117,1118],{"class":87,"line":198},[85,1119,163],{"emptyLinePlaceholder":162},[85,1121,1122,1124,1126,1128],{"class":87,"line":205},[85,1123,92],{"class":91},[85,1125,370],{"class":95},[85,1127,373],{"class":111},[85,1129,99],{"class":91},[85,1131,1132,1134,1136,1138,1140,1142,1144],{"class":87,"line":229},[85,1133,380],{"class":95},[85,1135,383],{"class":91},[85,1137,386],{"class":95},[85,1139,389],{"class":118},[85,1141,80],{"class":122},[85,1143,119],{"class":118},[85,1145,396],{"class":91},[85,1147,1148],{"class":87,"line":234},[85,1149,163],{"emptyLinePlaceholder":162},[85,1151,1152,1154,1156,1158,1160,1162,1165],{"class":87,"line":240},[85,1153,405],{"class":95},[85,1155,554],{"class":91},[85,1157,115],{"class":95},[85,1159,414],{"class":413},[85,1161,417],{"class":91},[85,1163,1164],{"class":118},"\"\"",[85,1166,427],{"class":91},[85,1168,1169,1171,1173],{"class":87,"line":267},[85,1170,270],{"class":91},[85,1172,370],{"class":95},[85,1174,99],{"class":91},[307,1176,1178],{"id":1177},"v-show-visibility","v-show: Visibility",[15,1180,1181,1183,1184,1187],{},[19,1182,29],{}," keeps the element in the DOM and toggles the CSS ",[19,1185,1186],{},"display"," property:",[76,1189,1191],{"className":78,"code":1190,"language":80,"meta":81,"style":81},"\u003Ctemplate>\n  \u003Cdiv v-show=\"name.length > 10\">Your name is too long!\u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[19,1192,1193,1201,1224],{"__ignoreMap":81},[85,1194,1195,1197,1199],{"class":87,"line":88},[85,1196,92],{"class":91},[85,1198,96],{"class":95},[85,1200,99],{"class":91},[85,1202,1203,1205,1207,1210,1212,1214,1216,1218,1220,1222],{"class":87,"line":102},[85,1204,105],{"class":91},[85,1206,498],{"class":95},[85,1208,1209],{"class":111}," v-show",[85,1211,115],{"class":95},[85,1213,119],{"class":118},[85,1215,1059],{"class":122},[85,1217,119],{"class":118},[85,1219,1064],{"class":91},[85,1221,498],{"class":95},[85,1223,99],{"class":91},[85,1225,1226,1228,1230],{"class":87,"line":135},[85,1227,270],{"class":91},[85,1229,96],{"class":95},[85,1231,99],{"class":91},[307,1233,1235],{"id":1234},"v-html-and-v-text","v-html and v-text",[15,1237,1238,1241,1242,1245,1246,1249],{},[19,1239,1240],{},"v-text"," sets the element's text, like the ",[19,1243,1244],{},"{{ }}"," interpolation does. ",[19,1247,1248],{},"v-html"," inserts the string as HTML.",[1251,1252,1253],"blockquote",{},[15,1254,1255,1256,1258],{},"Never use ",[19,1257,1248],{}," with user-provided or external content without sanitizing it first. Malicious HTML in that string is an XSS vulnerability. Regular interpolation treats everything as text and is the safe option.",[307,1260,1262],{"id":1261},"other-directives","Other Directives",[15,1264,1265],{},"Vue has five more directives that show up less often:",[801,1267,1268,1274,1280,1289,1295],{},[811,1269,1270,1273],{},[19,1271,1272],{},"v-slot"," receives the content of named and scoped slots.",[811,1275,1276,1279],{},[19,1277,1278],{},"v-once"," renders the element once and skips later updates.",[811,1281,1282,1285,1286,1288],{},[19,1283,1284],{},"v-pre"," skips compiling the element and its children, which is useful for showing ",[19,1287,1244],{}," literally.",[811,1290,1291,1294],{},[19,1292,1293],{},"v-cloak"," hides the template until it is compiled, in projects without a build step.",[811,1296,1297,1300],{},[19,1298,1299],{},"v-memo"," skips re-processing a part of the template while the listed values stay the same.",[39,1302,1304],{"id":1303},"v-if-or-v-show-which-one-should-you-choose","v-if or v-show: Which One Should You Choose?",[15,1306,1307,1308,1310,1311,1313,1314,37],{},"Both hide an element, but in different ways. ",[19,1309,25],{}," only renders the block when the condition is true and, when it changes, destroys and recreates the block with its components and listeners. ",[19,1312,29],{}," always renders the element and only toggles ",[19,1315,1186],{},[15,1317,1318,1319,1321,1322,1324],{},"The documentation's guidance is to prefer ",[19,1320,29],{}," when you toggle something very often, because toggling is cheaper. Prefer ",[19,1323,25],{}," when the condition rarely changes at runtime, because the block is not even created until it is needed.",[15,1326,1327,1329,1330,1333,1334,1336,1337,1339,1340,37],{},[19,1328,29],{}," has two limitations: it does not work on ",[19,1331,1332],{},"\u003Ctemplate>"," and it cannot be combined with ",[19,1335,1001],{},". To hide several elements at once, use ",[19,1338,25],{}," on a ",[19,1341,1332],{},[39,1343,1345],{"id":1344},"how-to-create-a-custom-directive-in-vue-3","How to Create a Custom Directive in Vue 3",[15,1347,1348],{},"A custom directive is an object with lifecycle functions that receive the DOM element. The Vue documentation recommends preferring declarative templates and keeping directives for when you need direct access to the element.",[307,1350,1352],{"id":1351},"a-local-directive-with-script-setup","A Local Directive with script setup",[15,1354,1355,1356,1358,1359,1362,1363,1366,1367,64],{},"Inside ",[19,1357,36],{},", any camelCase variable that starts with ",[19,1360,1361],{},"v"," becomes a directive. The variable ",[19,1364,1365],{},"vFocus"," is available in the template as ",[19,1368,1369],{},"v-focus",[76,1371,1373],{"className":78,"code":1372,"language":80,"meta":81,"style":81},"\u003Cscript setup>\nconst vFocus = {\n  mounted: (el) => el.focus()\n};\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cinput v-focus \u002F>\n\u003C\u002Ftemplate>\n",[19,1374,1375,1385,1397,1426,1431,1439,1443,1451,1462],{"__ignoreMap":81},[85,1376,1377,1379,1381,1383],{"class":87,"line":88},[85,1378,92],{"class":91},[85,1380,370],{"class":95},[85,1382,373],{"class":111},[85,1384,99],{"class":91},[85,1386,1387,1389,1392,1394],{"class":87,"line":102},[85,1388,405],{"class":95},[85,1390,1391],{"class":91}," vFocus ",[85,1393,115],{"class":95},[85,1395,1396],{"class":91}," {\n",[85,1398,1399,1402,1404,1407,1411,1414,1417,1420,1423],{"class":87,"line":135},[85,1400,1401],{"class":413},"  mounted",[85,1403,64],{"class":95},[85,1405,1406],{"class":91}," (",[85,1408,1410],{"class":1409},"sGEwX","el",[85,1412,1413],{"class":91},") ",[85,1415,1416],{"class":95},"=>",[85,1418,1419],{"class":91}," el.",[85,1421,1422],{"class":413},"focus",[85,1424,1425],{"class":91},"()\n",[85,1427,1428],{"class":87,"line":159},[85,1429,1430],{"class":91},"};\n",[85,1432,1433,1435,1437],{"class":87,"line":166},[85,1434,270],{"class":91},[85,1436,370],{"class":95},[85,1438,99],{"class":91},[85,1440,1441],{"class":87,"line":193},[85,1442,163],{"emptyLinePlaceholder":162},[85,1444,1445,1447,1449],{"class":87,"line":198},[85,1446,92],{"class":91},[85,1448,96],{"class":95},[85,1450,99],{"class":91},[85,1452,1453,1455,1457,1460],{"class":87,"line":205},[85,1454,105],{"class":91},[85,1456,464],{"class":95},[85,1458,1459],{"class":111}," v-focus",[85,1461,491],{"class":91},[85,1463,1464,1466,1468],{"class":87,"line":229},[85,1465,270],{"class":91},[85,1467,96],{"class":95},[85,1469,99],{"class":91},[15,1471,1472,1473,1476],{},"Here the ",[19,1474,1475],{},"mounted"," hook runs when the element is inserted into the DOM and focuses the field.",[307,1478,1480],{"id":1479},"global-registration-with-appdirective","Global Registration with app.directive",[15,1482,1483,1484,64],{},"If several parts of the application use the directive, write it in its own file and register it once with ",[19,1485,1486],{},"app.directive",[76,1488,1492],{"className":1489,"code":1490,"language":1491,"meta":81,"style":81},"language-ts shiki shiki-themes dracula","\u002F\u002F directives\u002Ffocus.ts\nimport type { Directive } from \"vue\";\n\nexport const vFocus: Directive\u003CHTMLElement> = {\n  mounted: (el) => el.focus()\n};\n","ts",[19,1493,1494,1499,1518,1522,1551,1571],{"__ignoreMap":81},[85,1495,1496],{"class":87,"line":88},[85,1497,1498],{"class":201},"\u002F\u002F directives\u002Ffocus.ts\n",[85,1500,1501,1503,1505,1508,1510,1512,1514,1516],{"class":87,"line":102},[85,1502,380],{"class":95},[85,1504,479],{"class":95},[85,1506,1507],{"class":91}," { Directive } ",[85,1509,386],{"class":95},[85,1511,389],{"class":118},[85,1513,80],{"class":122},[85,1515,119],{"class":118},[85,1517,396],{"class":91},[85,1519,1520],{"class":87,"line":135},[85,1521,163],{"emptyLinePlaceholder":162},[85,1523,1524,1527,1530,1533,1535,1539,1541,1544,1547,1549],{"class":87,"line":159},[85,1525,1526],{"class":95},"export",[85,1528,1529],{"class":95}," const",[85,1531,1532],{"class":91}," vFocus",[85,1534,64],{"class":95},[85,1536,1538],{"class":1537},"sCp4m"," Directive",[85,1540,92],{"class":91},[85,1542,1543],{"class":1409},"HTMLElement",[85,1545,1546],{"class":91},"> ",[85,1548,115],{"class":95},[85,1550,1396],{"class":91},[85,1552,1553,1555,1557,1559,1561,1563,1565,1567,1569],{"class":87,"line":166},[85,1554,1401],{"class":413},[85,1556,64],{"class":95},[85,1558,1406],{"class":91},[85,1560,1410],{"class":1409},[85,1562,1413],{"class":91},[85,1564,1416],{"class":95},[85,1566,1419],{"class":91},[85,1568,1422],{"class":413},[85,1570,1425],{"class":91},[85,1572,1573],{"class":87,"line":193},[85,1574,1430],{"class":91},[76,1576,1578],{"className":1489,"code":1577,"language":1491,"meta":81,"style":81},"\u002F\u002F main.ts\nimport { createApp } from \"vue\";\nimport App from \".\u002FApp.vue\";\nimport { vFocus } from \".\u002Fdirectives\u002Ffocus\";\n\nconst app = createApp(App);\n\napp.directive(\"focus\", vFocus);\napp.mount(\"#app\");\n",[19,1579,1580,1585,1602,1620,1638,1642,1657,1661,1680],{"__ignoreMap":81},[85,1581,1582],{"class":87,"line":88},[85,1583,1584],{"class":201},"\u002F\u002F main.ts\n",[85,1586,1587,1589,1592,1594,1596,1598,1600],{"class":87,"line":102},[85,1588,380],{"class":95},[85,1590,1591],{"class":91}," { createApp } ",[85,1593,386],{"class":95},[85,1595,389],{"class":118},[85,1597,80],{"class":122},[85,1599,119],{"class":118},[85,1601,396],{"class":91},[85,1603,1604,1606,1609,1611,1613,1616,1618],{"class":87,"line":135},[85,1605,380],{"class":95},[85,1607,1608],{"class":91}," App ",[85,1610,386],{"class":95},[85,1612,389],{"class":118},[85,1614,1615],{"class":122},".\u002FApp.vue",[85,1617,119],{"class":118},[85,1619,396],{"class":91},[85,1621,1622,1624,1627,1629,1631,1634,1636],{"class":87,"line":159},[85,1623,380],{"class":95},[85,1625,1626],{"class":91}," { vFocus } ",[85,1628,386],{"class":95},[85,1630,389],{"class":118},[85,1632,1633],{"class":122},".\u002Fdirectives\u002Ffocus",[85,1635,119],{"class":118},[85,1637,396],{"class":91},[85,1639,1640],{"class":87,"line":166},[85,1641,163],{"emptyLinePlaceholder":162},[85,1643,1644,1646,1649,1651,1654],{"class":87,"line":193},[85,1645,405],{"class":95},[85,1647,1648],{"class":91}," app ",[85,1650,115],{"class":95},[85,1652,1653],{"class":413}," createApp",[85,1655,1656],{"class":91},"(App);\n",[85,1658,1659],{"class":87,"line":198},[85,1660,163],{"emptyLinePlaceholder":162},[85,1662,1663,1666,1669,1671,1673,1675,1677],{"class":87,"line":205},[85,1664,1665],{"class":91},"app.",[85,1667,1668],{"class":413},"directive",[85,1670,417],{"class":91},[85,1672,119],{"class":118},[85,1674,1422],{"class":122},[85,1676,119],{"class":118},[85,1678,1679],{"class":91},", vFocus);\n",[85,1681,1682,1684,1687,1689,1691,1694,1696],{"class":87,"line":229},[85,1683,1665],{"class":91},[85,1685,1686],{"class":413},"mount",[85,1688,417],{"class":91},[85,1690,119],{"class":118},[85,1692,1693],{"class":122},"#app",[85,1695,119],{"class":118},[85,1697,427],{"class":91},[307,1699,1701],{"id":1700},"lifecycle-hooks","Lifecycle Hooks",[15,1703,1704],{},"A directive can implement these hooks, listed in the order they run:",[801,1706,1707,1713,1719,1724,1730,1736,1742],{},[811,1708,1709,1712],{},[19,1710,1711],{},"created",": before the element's attributes and listeners are applied.",[811,1714,1715,1718],{},[19,1716,1717],{},"beforeMount",": before the element is inserted into the DOM.",[811,1720,1721,1723],{},[19,1722,1475],{},": after the parent component and all its children are mounted.",[811,1725,1726,1729],{},[19,1727,1728],{},"beforeUpdate",": before the parent component updates.",[811,1731,1732,1735],{},[19,1733,1734],{},"updated",": after the parent component and its children update.",[811,1737,1738,1741],{},[19,1739,1740],{},"beforeUnmount",": before the parent component is unmounted.",[811,1743,1744,1747],{},[19,1745,1746],{},"unmounted",": after the parent component is unmounted.",[15,1749,1750,1751,1753,1754,26,1757,1760,1761,1764,1765,1767,1768,1771,1772,1775,1776,26,1778,1780,1781,1784,1785,1788,1789,1792,1793,1796,1797,1799],{},"All of them receive ",[19,1752,1410],{}," (the element), ",[19,1755,1756],{},"binding",[19,1758,1759],{},"vnode",". The update hooks also receive ",[19,1762,1763],{},"prevVnode",". The ",[19,1766,1756],{}," object carries the ",[19,1769,1770],{},"value"," passed to the directive, the ",[19,1773,1774],{},"oldValue"," (only in ",[19,1777,1728],{},[19,1779,1734],{},"), the ",[19,1782,1783],{},"arg",", the ",[19,1786,1787],{},"modifiers",", the component ",[19,1790,1791],{},"instance"," and the directive definition itself in ",[19,1794,1795],{},"dir",". Treat all of these except ",[19,1798,1410],{}," as read-only.",[307,1801,1803],{"id":1802},"value-argument-and-modifiers","Value, Argument and Modifiers",[15,1805,1806,1807,26,1809,64],{},"When the same behavior should run on mount and on every update, write the directive as a function. It is called on ",[19,1808,1475],{},[19,1810,1734],{},[76,1812,1814],{"className":1489,"code":1813,"language":1491,"meta":81,"style":81},"\u002F\u002F directives\u002Fhighlight.ts\nimport type { Directive } from \"vue\";\n\n\u002F\u002F usage: \u003Cp v-highlight:background.smooth=\"'#fff3b0'\">Text\u003C\u002Fp>\nexport const vHighlight: Directive\u003CHTMLElement, string> = (el, binding) => {\n  el.style.setProperty(binding.arg ?? \"color\", binding.value);\n\n  if (binding.modifiers.smooth) {\n    el.style.transition = \"all 0.3s\";\n  }\n};\n",[19,1815,1816,1821,1839,1843,1848,1888,1912,1916,1924,1940,1945],{"__ignoreMap":81},[85,1817,1818],{"class":87,"line":88},[85,1819,1820],{"class":201},"\u002F\u002F directives\u002Fhighlight.ts\n",[85,1822,1823,1825,1827,1829,1831,1833,1835,1837],{"class":87,"line":102},[85,1824,380],{"class":95},[85,1826,479],{"class":95},[85,1828,1507],{"class":91},[85,1830,386],{"class":95},[85,1832,389],{"class":118},[85,1834,80],{"class":122},[85,1836,119],{"class":118},[85,1838,396],{"class":91},[85,1840,1841],{"class":87,"line":135},[85,1842,163],{"emptyLinePlaceholder":162},[85,1844,1845],{"class":87,"line":159},[85,1846,1847],{"class":201},"\u002F\u002F usage: \u003Cp v-highlight:background.smooth=\"'#fff3b0'\">Text\u003C\u002Fp>\n",[85,1849,1850,1852,1854,1857,1859,1861,1863,1865,1867,1870,1872,1874,1876,1878,1880,1882,1884,1886],{"class":87,"line":166},[85,1851,1526],{"class":95},[85,1853,1529],{"class":95},[85,1855,1856],{"class":413}," vHighlight",[85,1858,64],{"class":95},[85,1860,1538],{"class":1537},[85,1862,92],{"class":91},[85,1864,1543],{"class":1409},[85,1866,292],{"class":91},[85,1868,1869],{"class":1537},"string",[85,1871,1546],{"class":91},[85,1873,115],{"class":95},[85,1875,1406],{"class":91},[85,1877,1410],{"class":1409},[85,1879,292],{"class":91},[85,1881,1756],{"class":1409},[85,1883,1413],{"class":91},[85,1885,1416],{"class":95},[85,1887,1396],{"class":91},[85,1889,1890,1893,1896,1899,1902,1904,1907,1909],{"class":87,"line":193},[85,1891,1892],{"class":91},"  el.style.",[85,1894,1895],{"class":413},"setProperty",[85,1897,1898],{"class":91},"(binding.arg ",[85,1900,1901],{"class":95},"??",[85,1903,389],{"class":118},[85,1905,1906],{"class":122},"color",[85,1908,119],{"class":118},[85,1910,1911],{"class":91},", binding.value);\n",[85,1913,1914],{"class":87,"line":198},[85,1915,163],{"emptyLinePlaceholder":162},[85,1917,1918,1921],{"class":87,"line":205},[85,1919,1920],{"class":95},"  if",[85,1922,1923],{"class":91}," (binding.modifiers.smooth) {\n",[85,1925,1926,1929,1931,1933,1936,1938],{"class":87,"line":229},[85,1927,1928],{"class":91},"    el.style.transition ",[85,1930,115],{"class":95},[85,1932,389],{"class":118},[85,1934,1935],{"class":122},"all 0.3s",[85,1937,119],{"class":118},[85,1939,396],{"class":91},[85,1941,1942],{"class":87,"line":234},[85,1943,1944],{"class":91},"  }\n",[85,1946,1947],{"class":87,"line":240},[85,1948,1430],{"class":91},[15,1950,1951,1952,1954,1955,1784,1958,1961,1962,1965,1966,1968,1969,37],{},"The ",[19,1953,1783],{}," is ",[19,1956,1957],{},"background",[19,1959,1960],{},"smooth"," modifier shows up in ",[19,1963,1964],{},"binding.modifiers"," and the ",[19,1967,1770],{}," is the color. When the directive needs several options, the value can be an object: ",[19,1970,1971],{},"v-highlight=\"{ color: 'white', duration: 300 }\"",[307,1973,1975],{"id":1974},"cleaning-up-listeners","Cleaning Up Listeners",[15,1977,1978,1979,1982,1983,1986],{},"Any directive that registers a listener on ",[19,1980,1981],{},"document"," or ",[19,1984,1985],{},"window",", an observer or a timer has to undo it when the element leaves the screen. The classic example is closing a menu when the user clicks outside of it:",[76,1988,1990],{"className":1489,"code":1989,"language":1491,"meta":81,"style":81},"\u002F\u002F directives\u002FclickOutside.ts\nimport type { Directive } from \"vue\";\n\ntype ElementWithListener = HTMLElement & {\n  _onClickOutside?: (event: MouseEvent) => void;\n};\n\nexport const vClickOutside: Directive\u003CElementWithListener, () => void> = {\n  mounted(el, binding) {\n    el._onClickOutside = (event) => {\n      if (!el.contains(event.target as Node)) {\n        binding.value();\n      }\n    };\n\n    document.addEventListener(\"click\", el._onClickOutside);\n  },\n\n  unmounted(el) {\n    if (el._onClickOutside) {\n      document.removeEventListener(\"click\", el._onClickOutside);\n      delete el._onClickOutside;\n    }\n  }\n};\n",[19,1991,1992,1997,2015,2019,2038,2065,2069,2073,2104,2119,2139,2167,2177,2182,2187,2191,2212,2218,2223,2235,2244,2263,2272,2278,2283],{"__ignoreMap":81},[85,1993,1994],{"class":87,"line":88},[85,1995,1996],{"class":201},"\u002F\u002F directives\u002FclickOutside.ts\n",[85,1998,1999,2001,2003,2005,2007,2009,2011,2013],{"class":87,"line":102},[85,2000,380],{"class":95},[85,2002,479],{"class":95},[85,2004,1507],{"class":91},[85,2006,386],{"class":95},[85,2008,389],{"class":118},[85,2010,80],{"class":122},[85,2012,119],{"class":118},[85,2014,396],{"class":91},[85,2016,2017],{"class":87,"line":135},[85,2018,163],{"emptyLinePlaceholder":162},[85,2020,2021,2024,2027,2030,2033,2036],{"class":87,"line":159},[85,2022,2023],{"class":95},"type",[85,2025,2026],{"class":1537}," ElementWithListener",[85,2028,2029],{"class":95}," =",[85,2031,2032],{"class":1537}," HTMLElement",[85,2034,2035],{"class":95}," &",[85,2037,1396],{"class":91},[85,2039,2040,2043,2046,2048,2051,2053,2056,2058,2060,2063],{"class":87,"line":166},[85,2041,2042],{"class":413},"  _onClickOutside",[85,2044,2045],{"class":95},"?:",[85,2047,1406],{"class":91},[85,2049,2050],{"class":1409},"event",[85,2052,64],{"class":95},[85,2054,2055],{"class":1537}," MouseEvent",[85,2057,1413],{"class":91},[85,2059,1416],{"class":95},[85,2061,2062],{"class":1537}," void",[85,2064,396],{"class":91},[85,2066,2067],{"class":87,"line":193},[85,2068,1430],{"class":91},[85,2070,2071],{"class":87,"line":198},[85,2072,163],{"emptyLinePlaceholder":162},[85,2074,2075,2077,2079,2082,2084,2086,2088,2091,2094,2096,2098,2100,2102],{"class":87,"line":205},[85,2076,1526],{"class":95},[85,2078,1529],{"class":95},[85,2080,2081],{"class":91}," vClickOutside",[85,2083,64],{"class":95},[85,2085,1538],{"class":1537},[85,2087,92],{"class":91},[85,2089,2090],{"class":1409},"ElementWithListener",[85,2092,2093],{"class":91},", () ",[85,2095,1416],{"class":95},[85,2097,2062],{"class":1537},[85,2099,1546],{"class":91},[85,2101,115],{"class":95},[85,2103,1396],{"class":91},[85,2105,2106,2108,2110,2112,2114,2116],{"class":87,"line":229},[85,2107,1401],{"class":413},[85,2109,417],{"class":91},[85,2111,1410],{"class":1409},[85,2113,292],{"class":91},[85,2115,1756],{"class":1409},[85,2117,2118],{"class":91},") {\n",[85,2120,2121,2124,2127,2129,2131,2133,2135,2137],{"class":87,"line":234},[85,2122,2123],{"class":91},"    el.",[85,2125,2126],{"class":413},"_onClickOutside",[85,2128,2029],{"class":95},[85,2130,1406],{"class":91},[85,2132,2050],{"class":1409},[85,2134,1413],{"class":91},[85,2136,1416],{"class":95},[85,2138,1396],{"class":91},[85,2140,2141,2144,2146,2149,2152,2155,2158,2161,2164],{"class":87,"line":240},[85,2142,2143],{"class":95},"      if",[85,2145,1406],{"class":91},[85,2147,2148],{"class":95},"!",[85,2150,2151],{"class":91},"el.",[85,2153,2154],{"class":413},"contains",[85,2156,2157],{"class":91},"(event.target ",[85,2159,2160],{"class":95},"as",[85,2162,2163],{"class":1537}," Node",[85,2165,2166],{"class":91},")) {\n",[85,2168,2169,2172,2174],{"class":87,"line":267},[85,2170,2171],{"class":91},"        binding.",[85,2173,1770],{"class":413},[85,2175,2176],{"class":91},"();\n",[85,2178,2179],{"class":87,"line":756},[85,2180,2181],{"class":91},"      }\n",[85,2183,2184],{"class":87,"line":762},[85,2185,2186],{"class":91},"    };\n",[85,2188,2189],{"class":87,"line":973},[85,2190,163],{"emptyLinePlaceholder":162},[85,2192,2194,2197,2200,2202,2204,2207,2209],{"class":87,"line":2193},16,[85,2195,2196],{"class":91},"    document.",[85,2198,2199],{"class":413},"addEventListener",[85,2201,417],{"class":91},[85,2203,119],{"class":118},[85,2205,2206],{"class":122},"click",[85,2208,119],{"class":118},[85,2210,2211],{"class":91},", el._onClickOutside);\n",[85,2213,2215],{"class":87,"line":2214},17,[85,2216,2217],{"class":91},"  },\n",[85,2219,2221],{"class":87,"line":2220},18,[85,2222,163],{"emptyLinePlaceholder":162},[85,2224,2226,2229,2231,2233],{"class":87,"line":2225},19,[85,2227,2228],{"class":413},"  unmounted",[85,2230,417],{"class":91},[85,2232,1410],{"class":1409},[85,2234,2118],{"class":91},[85,2236,2238,2241],{"class":87,"line":2237},20,[85,2239,2240],{"class":95},"    if",[85,2242,2243],{"class":91}," (el._onClickOutside) {\n",[85,2245,2247,2250,2253,2255,2257,2259,2261],{"class":87,"line":2246},21,[85,2248,2249],{"class":91},"      document.",[85,2251,2252],{"class":413},"removeEventListener",[85,2254,417],{"class":91},[85,2256,119],{"class":118},[85,2258,2206],{"class":122},[85,2260,119],{"class":118},[85,2262,2211],{"class":91},[85,2264,2266,2269],{"class":87,"line":2265},22,[85,2267,2268],{"class":95},"      delete",[85,2270,2271],{"class":91}," el._onClickOutside;\n",[85,2273,2275],{"class":87,"line":2274},23,[85,2276,2277],{"class":91},"    }\n",[85,2279,2281],{"class":87,"line":2280},24,[85,2282,1944],{"class":91},[85,2284,2286],{"class":87,"line":2285},25,[85,2287,1430],{"class":91},[15,2289,2290,2291,2293,2294,2296,2297,2300,2301,2303],{},"The function is stored on the element so ",[19,2292,1746],{}," removes exactly the same reference that ",[19,2295,1475],{}," registered. Without that, the listener stays alive after the element is gone. This example reads ",[19,2298,2299],{},"binding.value"," only on mount. If the function you pass can change, update the reference in the ",[19,2302,1734],{}," hook too.",[39,2305,2307],{"id":2306},"directive-composable-or-component","Directive, Composable or Component?",[15,2309,2310],{},"A directive fits when the logic has to touch one specific element, like focusing a field. If the logic has state or works without being tied to an element, like a reusable debounce, a composable is a better fit. When there is visual structure, like an accessible tooltip or a menu with keyboard support and submenus, a component is the right choice.",[15,2312,2313],{},"A good tooltip needs positioning, focus, keyboard support and the Esc key. A directive that tries to cover all of that tends to end up more complicated than the equivalent component.",[39,2315,2317],{"id":2316},"how-to-use-custom-directives-in-nuxt-4","How to Use Custom Directives in Nuxt 4",[15,2319,2320,2321,2324,2325,2328,2329,2332],{},"In Nuxt, a global directive is registered in a plugin inside ",[19,2322,2323],{},"app\u002Fplugins\u002F",", using ",[19,2326,2327],{},"nuxtApp.vueApp.directive",". Because Nuxt renders the page on the server, there is one more rule: during SSR, Vue ignores a directive's hooks, since they manipulate the DOM and the server has no DOM. If the directive needs to add an attribute to the generated HTML, use the ",[19,2330,2331],{},"getSSRProps"," hook, which returns the props to render:",[76,2334,2336],{"className":1489,"code":2335,"language":1491,"meta":81,"style":81},"\u002F\u002F app\u002Fplugins\u002Fdirectives.ts\nexport default defineNuxtPlugin((nuxtApp) => {\n  nuxtApp.vueApp.directive(\"focus\", {\n    mounted: (el: HTMLElement) => el.focus(),\n    getSSRProps: () => ({ autofocus: true })\n  });\n});\n",[19,2337,2338,2343,2365,2383,2409,2432,2437],{"__ignoreMap":81},[85,2339,2340],{"class":87,"line":88},[85,2341,2342],{"class":201},"\u002F\u002F app\u002Fplugins\u002Fdirectives.ts\n",[85,2344,2345,2347,2350,2353,2356,2359,2361,2363],{"class":87,"line":102},[85,2346,1526],{"class":95},[85,2348,2349],{"class":95}," default",[85,2351,2352],{"class":413}," defineNuxtPlugin",[85,2354,2355],{"class":91},"((",[85,2357,2358],{"class":1409},"nuxtApp",[85,2360,1413],{"class":91},[85,2362,1416],{"class":95},[85,2364,1396],{"class":91},[85,2366,2367,2370,2372,2374,2376,2378,2380],{"class":87,"line":135},[85,2368,2369],{"class":91},"  nuxtApp.vueApp.",[85,2371,1668],{"class":413},[85,2373,417],{"class":91},[85,2375,119],{"class":118},[85,2377,1422],{"class":122},[85,2379,119],{"class":118},[85,2381,2382],{"class":91},", {\n",[85,2384,2385,2388,2390,2392,2394,2396,2398,2400,2402,2404,2406],{"class":87,"line":159},[85,2386,2387],{"class":413},"    mounted",[85,2389,64],{"class":95},[85,2391,1406],{"class":91},[85,2393,1410],{"class":1409},[85,2395,64],{"class":95},[85,2397,2032],{"class":1537},[85,2399,1413],{"class":91},[85,2401,1416],{"class":95},[85,2403,1419],{"class":91},[85,2405,1422],{"class":413},[85,2407,2408],{"class":91},"(),\n",[85,2410,2411,2414,2416,2419,2421,2424,2426,2429],{"class":87,"line":166},[85,2412,2413],{"class":413},"    getSSRProps",[85,2415,64],{"class":95},[85,2417,2418],{"class":91}," () ",[85,2420,1416],{"class":95},[85,2422,2423],{"class":91}," ({ autofocus",[85,2425,64],{"class":95},[85,2427,2428],{"class":904}," true",[85,2430,2431],{"class":91}," })\n",[85,2433,2434],{"class":87,"line":193},[85,2435,2436],{"class":91},"  });\n",[85,2438,2439],{"class":87,"line":198},[85,2440,2441],{"class":91},"});\n",[15,2443,2444,2445,2448,2449,2452,2453,2455,2456,2459],{},"With this plugin, ",[19,2446,2447],{},"\u003Cinput v-focus \u002F>"," leaves the server as ",[19,2450,2451],{},"\u003Cinput autofocus>",". Without ",[19,2454,2331],{},", it would be a bare ",[19,2457,2458],{},"\u003Cinput>",", and focus would only arrive after hydration.",[15,2461,2462,2463,2466,2467,2470,2471,2474],{},"The Nuxt documentation asks you to register the directive on both client and server, unless it is only used on one side. For a browser-only directive, like ",[19,2464,2465],{},"v-click-outside",", create the plugin with a ",[19,2468,2469],{},".client"," suffix and a ",[19,2472,2473],{},".server"," plugin with an empty directive, only so Vue recognizes the name:",[76,2476,2478],{"className":1489,"code":2477,"language":1491,"meta":81,"style":81},"\u002F\u002F app\u002Fplugins\u002Fclick-outside.client.ts\nimport { vClickOutside } from \"~\u002Fdirectives\u002FclickOutside\";\n\nexport default defineNuxtPlugin((nuxtApp) => {\n  nuxtApp.vueApp.directive(\"click-outside\", vClickOutside);\n});\n",[19,2479,2480,2485,2503,2507,2525,2543],{"__ignoreMap":81},[85,2481,2482],{"class":87,"line":88},[85,2483,2484],{"class":201},"\u002F\u002F app\u002Fplugins\u002Fclick-outside.client.ts\n",[85,2486,2487,2489,2492,2494,2496,2499,2501],{"class":87,"line":102},[85,2488,380],{"class":95},[85,2490,2491],{"class":91}," { vClickOutside } ",[85,2493,386],{"class":95},[85,2495,389],{"class":118},[85,2497,2498],{"class":122},"~\u002Fdirectives\u002FclickOutside",[85,2500,119],{"class":118},[85,2502,396],{"class":91},[85,2504,2505],{"class":87,"line":135},[85,2506,163],{"emptyLinePlaceholder":162},[85,2508,2509,2511,2513,2515,2517,2519,2521,2523],{"class":87,"line":159},[85,2510,1526],{"class":95},[85,2512,2349],{"class":95},[85,2514,2352],{"class":413},[85,2516,2355],{"class":91},[85,2518,2358],{"class":1409},[85,2520,1413],{"class":91},[85,2522,1416],{"class":95},[85,2524,1396],{"class":91},[85,2526,2527,2529,2531,2533,2535,2538,2540],{"class":87,"line":166},[85,2528,2369],{"class":91},[85,2530,1668],{"class":413},[85,2532,417],{"class":91},[85,2534,119],{"class":118},[85,2536,2537],{"class":122},"click-outside",[85,2539,119],{"class":118},[85,2541,2542],{"class":91},", vClickOutside);\n",[85,2544,2545],{"class":87,"line":193},[85,2546,2441],{"class":91},[76,2548,2550],{"className":1489,"code":2549,"language":1491,"meta":81,"style":81},"\u002F\u002F app\u002Fplugins\u002Fclick-outside.server.ts\nexport default defineNuxtPlugin((nuxtApp) => {\n  nuxtApp.vueApp.directive(\"click-outside\", {});\n});\n",[19,2551,2552,2557,2575,2592],{"__ignoreMap":81},[85,2553,2554],{"class":87,"line":88},[85,2555,2556],{"class":201},"\u002F\u002F app\u002Fplugins\u002Fclick-outside.server.ts\n",[85,2558,2559,2561,2563,2565,2567,2569,2571,2573],{"class":87,"line":102},[85,2560,1526],{"class":95},[85,2562,2349],{"class":95},[85,2564,2352],{"class":413},[85,2566,2355],{"class":91},[85,2568,2358],{"class":1409},[85,2570,1413],{"class":91},[85,2572,1416],{"class":95},[85,2574,1396],{"class":91},[85,2576,2577,2579,2581,2583,2585,2587,2589],{"class":87,"line":135},[85,2578,2369],{"class":91},[85,2580,1668],{"class":413},[85,2582,417],{"class":91},[85,2584,119],{"class":118},[85,2586,2537],{"class":122},[85,2588,119],{"class":118},[85,2590,2591],{"class":91},", {});\n",[85,2593,2594],{"class":87,"line":159},[85,2595,2441],{"class":91},[39,2597,2599],{"id":2598},"what-changed-in-directives-from-vue-2-to-vue-3","What Changed in Directives from Vue 2 to Vue 3?",[15,2601,2602],{},"Many older tutorials still use the Vue 2 hooks, and they do not work in Vue 3. Here is the mapping:",[801,2604,2605,2613,2620,2627,2634,2642],{},[811,2606,2607,2610,2611,37],{},[19,2608,2609],{},"bind"," became ",[19,2612,1717],{},[811,2614,2615,2610,2618,37],{},[19,2616,2617],{},"inserted",[19,2619,1475],{},[811,2621,2622,2610,2625,37],{},[19,2623,2624],{},"componentUpdated",[19,2626,1734],{},[811,2628,2629,2610,2632,37],{},[19,2630,2631],{},"unbind",[19,2633,1746],{},[811,2635,2636,2639,2640,37],{},[19,2637,2638],{},"update"," was removed, because it was redundant with ",[19,2641,1734],{},[811,2643,2644,292,2646,26,2648,2650],{},[19,2645,1711],{},[19,2647,1728],{},[19,2649,1740],{}," are new.",[15,2652,1951,2653,2655,2656,2659,2660,2663,2664,37],{},[19,2654,1756],{}," object also lost the ",[19,2657,2658],{},"expression"," string, and the component instance moved from ",[19,2661,2662],{},"vnode.context"," to ",[19,2665,2666],{},"binding.instance",[39,2668,2670],{"id":2669},"what-are-the-most-common-mistakes-with-directives","What Are the Most Common Mistakes with Directives?",[801,2672,2673,2684,2690,2696,2701,2704,2707],{},[811,2674,2675,2676,26,2678,2680,2681,2683],{},"Using ",[19,2677,25],{},[19,2679,53],{}," on the same element. ",[19,2682,25],{}," is evaluated first, and the documentation does not recommend the combination. Filter the list in a computed property or split it into two elements.",[811,2685,2686,2687,2689],{},"Using the index as ",[19,2688,985],{}," in lists that change.",[811,2691,2692,2693,2695],{},"Applying ",[19,2694,1248],{}," to text that came from a user.",[811,2697,2698,2699,37],{},"Registering a listener or timer without removing it in ",[19,2700,1746],{},[811,2702,2703],{},"Applying a custom directive to a component with more than one root element. The directive is ignored and Vue emits a warning. The documentation does not recommend custom directives on components.",[811,2705,2706],{},"Counting on DOM manipulation during SSR.",[811,2708,2709],{},"Creating a directive for something that would be simpler as a component.",[39,2711,2713],{"id":2712},"frequently-asked-questions","Frequently Asked Questions",[307,2715,2717],{"id":2716},"what-are-directives-in-vue-1","What are directives in Vue?",[15,2719,2720,2721,2723],{},"They are special template attributes, prefixed with ",[19,2722,21],{},", that apply reactive behavior to an element, such as changing attributes, listening to events, repeating elements or controlling rendering.",[307,2725,2727],{"id":2726},"what-is-the-difference-between-v-if-and-v-show","What is the difference between v-if and v-show?",[15,2729,2730,2732,2733,2735,2736,2738,2739,2741,2742,2744],{},[19,2731,25],{}," mounts and unmounts the block depending on the condition. ",[19,2734,29],{}," keeps the element in the DOM and toggles ",[19,2737,1186],{},". Use ",[19,2740,29],{}," for frequent toggles and ",[19,2743,25],{}," when the condition rarely changes.",[307,2746,2748],{"id":2747},"can-i-use-the-array-index-as-the-key-in-v-for","Can I use the array index as the key in v-for?",[15,2750,2751],{},"Only in static lists that never change order or size. In lists that change, use a stable id from the item itself.",[307,2753,2755],{"id":2754},"how-do-i-create-a-custom-directive-with-script-setup","How do I create a custom directive with script setup?",[15,2757,2758,2759,2761,2762,2764,2765,2767],{},"Declare a camelCase variable that starts with ",[19,2760,1361],{},", like ",[19,2763,1365],{},", and use it in the template as ",[19,2766,1369],{},". Vue treats that as local registration.",[307,2769,2771],{"id":2770},"when-should-i-use-a-directive-instead-of-a-composable","When should I use a directive instead of a composable?",[15,2773,2774],{},"Use a directive when the logic has to manipulate a DOM element directly. If the logic has state or does not depend on a specific element, prefer a composable.",[307,2776,2778],{"id":2777},"do-custom-directives-work-with-ssr-in-nuxt","Do custom directives work with SSR in Nuxt?",[15,2780,2781,2782,2784,2785,2787,2788,2790],{},"The hooks that touch the DOM do not run on the server. To generate attributes in the server HTML, implement ",[19,2783,2331],{},". For a directive that only makes sense in the browser, register it in a ",[19,2786,2469],{}," plugin and create a ",[19,2789,2473],{}," stub.",[39,2792,2794],{"id":2793},"conclusion","Conclusion",[15,2796,2797,2798,2800,2801,26,2803,2805],{},"To pick the right tool, start with the element: if the logic has to touch it, use a directive; if it has state and can be reused, use a composable; if it has visual structure, use a component. Among the built-in directives, swap the index for a stable id in ",[19,2799,53],{}," and choose between ",[19,2802,25],{},[19,2804,29],{}," by how often the toggle happens.",[15,2807,2808,2809,292,2815,292,2820,26,2825,37],{},"To go deeper, read the documentation pages on ",[108,2810,2814],{"href":2811,"rel":2812},"https:\u002F\u002Fvuejs.org\u002Fguide\u002Freusability\u002Fcustom-directives.html",[2813],"nofollow","custom directives",[108,2816,2819],{"href":2817,"rel":2818},"https:\u002F\u002Fvuejs.org\u002Fguide\u002Fessentials\u002Fconditional.html",[2813],"conditional rendering",[108,2821,2824],{"href":2822,"rel":2823},"https:\u002F\u002Fvuejs.org\u002Fguide\u002Fessentials\u002Flist.html",[2813],"list rendering",[108,2826,2829],{"href":2827,"rel":2828},"https:\u002F\u002Fnuxt.com\u002Fdocs\u002F4.x\u002Fdirectory-structure\u002Fapp\u002Fplugins",[2813],"Nuxt plugins",[2831,2832,2833],"style",{},"html pre.shiki code .sCdxs, html code.shiki .sCdxs{--shiki-default:#F8F8F2}html pre.shiki code .s0Tla, html code.shiki .s0Tla{--shiki-default:#FF79C6}html pre.shiki code .sY_PY, html code.shiki .sY_PY{--shiki-default:#50FA7B;--shiki-default-font-style:italic}html pre.shiki code .seVfx, html code.shiki .seVfx{--shiki-default:#E9F284}html pre.shiki code .s-mGx, html code.shiki .s-mGx{--shiki-default:#F1FA8C}html pre.shiki code .shSDL, html code.shiki .shSDL{--shiki-default:#6272A4}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 pre.shiki code .sAOxA, html code.shiki .sAOxA{--shiki-default:#50FA7B}html pre.shiki code .sIQBb, html code.shiki .sIQBb{--shiki-default:#BD93F9}html pre.shiki code .sGEwX, html code.shiki .sGEwX{--shiki-default:#FFB86C;--shiki-default-font-style:italic}html pre.shiki code .sCp4m, html code.shiki .sCp4m{--shiki-default:#8BE9FD;--shiki-default-font-style:italic}",{"title":81,"searchDepth":102,"depth":102,"links":2835},[2836,2837,2838,2848,2849,2856,2857,2858,2859,2860,2868],{"id":41,"depth":102,"text":42},{"id":57,"depth":102,"text":58},{"id":304,"depth":102,"text":305,"children":2839},[2840,2841,2842,2843,2844,2845,2846,2847],{"id":309,"depth":135,"text":310},{"id":438,"depth":135,"text":439},{"id":593,"depth":135,"text":594},{"id":771,"depth":135,"text":772},{"id":989,"depth":135,"text":990},{"id":1177,"depth":135,"text":1178},{"id":1234,"depth":135,"text":1235},{"id":1261,"depth":135,"text":1262},{"id":1303,"depth":102,"text":1304},{"id":1344,"depth":102,"text":1345,"children":2850},[2851,2852,2853,2854,2855],{"id":1351,"depth":135,"text":1352},{"id":1479,"depth":135,"text":1480},{"id":1700,"depth":135,"text":1701},{"id":1802,"depth":135,"text":1803},{"id":1974,"depth":135,"text":1975},{"id":2306,"depth":102,"text":2307},{"id":2316,"depth":102,"text":2317},{"id":2598,"depth":102,"text":2599},{"id":2669,"depth":102,"text":2670},{"id":2712,"depth":102,"text":2713,"children":2861},[2862,2863,2864,2865,2866,2867],{"id":2716,"depth":135,"text":2717},{"id":2726,"depth":135,"text":2727},{"id":2747,"depth":135,"text":2748},{"id":2754,"depth":135,"text":2755},{"id":2770,"depth":135,"text":2771},{"id":2777,"depth":135,"text":2778},{"id":2793,"depth":102,"text":2794},[2870],"vuejs","Learn how to use built-in directives and create custom directives in Vue 3, with hooks, keys, modifiers and the SSR caveats in Nuxt, plus practical examples.","what-are-directives-in-vue-and-how-to-implement-them","md",{},"\u002Fen\u002Fblog\u002Fwhat-are-directives-in-vue-and-how-to-implement-them","o-que-sao-diretivas-no-vue-e-como-implementa-las","2025-03-21",{"title":5,"description":2871},{"loc":2875,"lastmod":2880},"2026-10-06","en\u002Fblog\u002Fwhat-are-directives-in-vue-and-how-to-implement-them",1985,"MP9b1GahnutCQGJ7G6uaQ8OKz9FbuFu6Qf0wfyxt85A",[2885,2894,2902,2910,2917,2925,2932,2940,2947,2955,2961,2969,2976,2982,2984],{"id":2886,"path":2887,"title":2888,"articleCover":2889,"categoriesIds":2890,"publishedAt":2893},"blogEn\u002Fen\u002Fblog\u002Fcore-web-vitals-how-user-experience-affects-seo.md","\u002Fen\u002Fblog\u002Fcore-web-vitals-how-user-experience-affects-seo","Core Web Vitals and SEO: How User Experience Affects Your Site","\u002Fimages\u002Fen\u002Fblog\u002Fseo\u002Fweb-vitals\u002Fcore-web-vitals-how-user-experience-affects-seo.webp",[2891,2892],"seo","web-vitals","2024-10-25",{"id":2895,"path":2896,"title":2897,"articleCover":2898,"categoriesIds":2899,"publishedAt":2901},"blogEn\u002Fen\u002Fblog\u002Ffree-developer-tools-hub.md","\u002Fen\u002Fblog\u002Ffree-developer-tools-hub","I Built a Free Web Tools Hub for Developers","\u002Fimages\u002Fen\u002Fblog\u002Ftools\u002Ffree-developer-tools-hub.webp",[2900],"tools","2026-01-06",{"id":2903,"path":2904,"title":2905,"articleCover":2906,"categoriesIds":2907,"publishedAt":2909},"blogEn\u002Fen\u002Fblog\u002Fhow-the-routing-system-works-in-nuxt.md","\u002Fen\u002Fblog\u002Fhow-the-routing-system-works-in-nuxt","Nuxt Routing: Dynamic, Nested and Catch-All Routes","\u002Fimages\u002Fblog\u002Fnuxt\u002Fnuxt-routing-thumb.webp",[2908,2870],"nuxt","2025-03-12",{"id":2911,"path":2912,"title":2913,"articleCover":2914,"categoriesIds":2915,"publishedAt":2916},"blogEn\u002Fen\u002Fblog\u002Fhow-to-add-special-characters-on-i18n.md","\u002Fen\u002Fblog\u002Fhow-to-add-special-characters-on-i18n","How to Add Special Characters in i18N Translations","\u002Fimages\u002Fblog\u002Fi18n\u002Fi18n-special-characters-on-nuxtjs-thumb.webp",[2908,2870],"2025-02-02",{"id":2918,"path":2919,"title":2920,"articleCover":2921,"categoriesIds":2922,"publishedAt":2924},"blogEn\u002Fen\u002Fblog\u002Fhow-to-create-and-set-up-ssh-key-github.md","\u002Fen\u002Fblog\u002Fhow-to-create-and-set-up-ssh-key-github","SSH Key in Git: How to Set Up an SSH Key for GitHub","\u002Fimages\u002Fen\u002Fblog\u002Fgit\u002Fhow-to-create-and-set-up-ssh-key-github-thumb.webp",[2923],"git","2025-02-04",{"id":2926,"path":2927,"title":2928,"articleCover":2929,"categoriesIds":2930,"publishedAt":2931},"blogEn\u002Fen\u002Fblog\u002Fhow-to-create-structured-data-with-nuxtjs.md","\u002Fen\u002Fblog\u002Fhow-to-create-structured-data-with-nuxtjs","What is Structured Data and How to Add it in Nuxt.JS","\u002Fimages\u002Fen\u002Fblog\u002Fseo\u002Fstructured-data\u002Fstructured-data-thumb-1.webp",[2908,2870,2891],"2025-01-22",{"id":2933,"path":2934,"title":2935,"articleCover":2936,"categoriesIds":2937,"publishedAt":2939},"blogEn\u002Fen\u002Fblog\u002Fhow-to-deal-with-envy-from-other-programmers.md","\u002Fen\u002Fblog\u002Fhow-to-deal-with-envy-from-other-programmers","How to Deal with Envy from Other Programmers in Your Career","\u002Fimages\u002Fen\u002Fblog\u002Fcareer\u002Fa-nail-that-stands-out-gets-hammered.webp",[2938],"career","2025-08-29",{"id":2941,"path":2942,"title":2943,"articleCover":2944,"categoriesIds":2945,"publishedAt":2946},"blogEn\u002Fen\u002Fblog\u002Fhow-to-use-middlewares-nuxtjs.md","\u002Fen\u002Fblog\u002Fhow-to-use-middlewares-nuxtjs","Middlewares: What They Are and How to Use Them in Nuxt.JS","\u002Fimages\u002Fblog\u002Fnuxt\u002Ffront-end-middlewares-thumb.webp",[2908,2870],"2025-02-03",{"id":2948,"path":2949,"title":2950,"articleCover":2951,"categoriesIds":2952,"publishedAt":2954},"blogEn\u002Fen\u002Fblog\u002Fhow-to-validate-cpf-with-javascript.md","\u002Fen\u002Fblog\u002Fhow-to-validate-cpf-with-javascript","How to validate a CPF with JavaScript","\u002Fimages\u002Fen\u002Fblog\u002Fjavascript\u002Fhow-to-validate-cpf-with-javascript.webp",[2953,2900],"javascript","2026-10-04",{"id":2956,"path":2957,"title":2958,"articleCover":2959,"categoriesIds":2960,"publishedAt":2954},"blogEn\u002Fen\u002Fblog\u002Fhow-to-validate-credit-card-with-javascript.md","\u002Fen\u002Fblog\u002Fhow-to-validate-credit-card-with-javascript","How to validate a credit card with JavaScript (Luhn algorithm)","\u002Fimages\u002Fen\u002Fblog\u002Fjavascript\u002Fhow-to-validate-credit-card-with-javascript.webp",[2953,2900],{"id":2962,"path":2963,"title":2964,"articleCover":2965,"categoriesIds":2966,"publishedAt":2968},"blogEn\u002Fen\u002Fblog\u002Frecovering-lost-files-in-git-with-vscode.md","\u002Fen\u002Fblog\u002Frecovering-lost-files-in-git-with-vscode","Recover Lost Files in Git Without a Commit Using VS Code Local History","\u002Fimages\u002Fen\u002Fblog\u002Fvscode\u002Fhow-to-recover-lost-files-in-git-using-vscode.webp",[2923,2967],"vscode","2025-01-21",{"id":2970,"path":2971,"title":2972,"articleCover":2973,"categoriesIds":2974,"publishedAt":2975},"blogEn\u002Fen\u002Fblog\u002Fvercel-buys-nuxt-labs.md","\u002Fen\u002Fblog\u002Fvercel-buys-nuxt-labs","Vercel Acquired Nuxt Labs! What Does This Mean for Nuxt?","\u002Fimages\u002Fen\u002Fblog\u002Fnuxt\u002Fvercel-buys-nuxt-labs.webp",[2908],"2025-07-17",{"id":2977,"path":2978,"title":2979,"articleCover":2980,"categoriesIds":2981,"publishedAt":2880},"blogEn\u002Fen\u002Fblog\u002Fvue-vapor-mode-what-it-is-and-how-to-use-it.md","\u002Fen\u002Fblog\u002Fvue-vapor-mode-what-it-is-and-how-to-use-it","Vue Vapor Mode: what it is and what changes in Vue 3.6","\u002Fimages\u002Fen\u002Fblog\u002Fvue\u002Fvue-vapor-mode-what-it-is-and-how-to-use-it.webp",[2870,2908],{"id":4,"path":2875,"title":5,"articleCover":6,"categoriesIds":2983,"publishedAt":2877},[2870],{"id":2985,"path":2986,"title":2987,"articleCover":2988,"categoriesIds":2989,"publishedAt":2990},"blogEn\u002Fen\u002Fblog\u002Fwhat-is-the-difference-between-composition-api-and-options-api-in-vuejs.md","\u002Fen\u002Fblog\u002Fwhat-is-the-difference-between-composition-api-and-options-api-in-vuejs","Composition API vs Options API in Vue.js: What's the Difference?","\u002Fimages\u002Fen\u002Fblog\u002Fvue\u002Fwhat-is-the-difference-between-composition-api-and-options-api-in-vuejs.webp",[2870],"2025-02-20",1791682335958]