[{"data":1,"prerenderedAt":2558},["ShallowReactive",2],{"page-\u002Fvue\u002F05-components-basics":3},{"id":4,"title":5,"body":6,"description":2551,"extension":2552,"meta":2553,"navigation":93,"path":2554,"seo":2555,"stem":2556,"__hash__":2557},"content\u002Fvue\u002F05-components-basics.md","Vue 3 Engineering Reference — Components Basics",{"type":7,"value":8,"toc":2540},"minimark",[9,14,19,578,582,858,862,1280,1288,1599,1603,2536],[10,11,13],"h1",{"id":12},"_05-components-basics","05 — Components Basics",[15,16,18],"h2",{"id":17},"sfc-compilation-script-setup-macros","SFC Compilation — script setup Macros",[20,21,24],"code-wrapper",{"filename":22,"language":23},"UserProfile.vue","vue",[25,26,30],"pre",{"className":27,"code":28,"language":23,"meta":29,"style":29},"language-vue shiki shiki-themes github-light github-dark","\u003Cscript setup lang=\"ts\">\n\u002F\u002F ── defineProps, defineEmits, defineExpose are COMPILER MACROS ──\n\u002F\u002F They look like functions but are resolved at BUILD time by the Vue SFC compiler.\n\u002F\u002F No runtime import needed — they're not real functions, they're compiler directives.\n\u002F\u002F The compiler transforms them into setup() return values.\n\n\u002F\u002F ── 1. defineProps — typed props via generic ──\nconst props = defineProps\u003C{\n  userId: number\n  role?: 'admin' | 'user' | 'guest'  \u002F\u002F optional union\n  tags?: string[]\n}>()\n\n\u002F\u002F ── withDefaults: provide defaults for optional props (TS-only) ──\n\u002F\u002F Required because TS interface defaults don't exist at runtime.\nconst { role = 'user', tags = [] } = withDefaults(props, {\n  role: 'user',\n  tags: () => [],  \u002F\u002F factory function for non-primitive defaults (fresh per instance)\n})\n\n\u002F\u002F ── 2. defineEmits — typed events ──\nconst emit = defineEmits\u003C{\n  (e: 'update', userId: number): void           \u002F\u002F named event with payload\n  (e: 'delete', payload: { id: number; soft: boolean }): void\n  (e: 'cancel'): void                            \u002F\u002F event with no payload\n}>()\n\n\u002F\u002F ── 3. defineExpose — explicitly expose internals to parent via template refs ──\n\u002F\u002F \u003Cscript setup> components are CLOSED by default — parent ref only gets the DOM.\n\u002F\u002F defineExpose opens a controlled API surface.\nfunction save() { \u002F* ... *\u002F }\nfunction reset() { \u002F* ... *\u002F }\ndefineExpose({ save, reset })\n\u002F\u002F Parent: const childRef = ref(); childRef.value?.save()\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003Cp>User: {{ userId }}\u003C\u002Fp>\n    \u003Cp>Role: {{ role }}\u003C\u002Fp>\n    \u003Cbutton @click=\"emit('update', userId)\">Update\u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n","",[31,32,33,63,70,76,82,88,95,101,121,134,160,174,180,185,191,197,231,243,260,266,271,277,292,327,374,395,400,405,411,417,423,441,455,464,470,480,485,495,506,522,536,559,569],"code",{"__ignoreMap":29},[34,35,38,42,46,50,53,56,60],"span",{"class":36,"line":37},"line",1,[34,39,41],{"class":40},"ssxIu","\u003C",[34,43,45],{"class":44},"sk71V","script",[34,47,49],{"class":48},"sIsaT"," setup",[34,51,52],{"class":48}," lang",[34,54,55],{"class":40},"=",[34,57,59],{"class":58},"sJ6F3","\"ts\"",[34,61,62],{"class":40},">\n",[34,64,66],{"class":36,"line":65},2,[34,67,69],{"class":68},"sdCPZ","\u002F\u002F ── defineProps, defineEmits, defineExpose are COMPILER MACROS ──\n",[34,71,73],{"class":36,"line":72},3,[34,74,75],{"class":68},"\u002F\u002F They look like functions but are resolved at BUILD time by the Vue SFC compiler.\n",[34,77,79],{"class":36,"line":78},4,[34,80,81],{"class":68},"\u002F\u002F No runtime import needed — they're not real functions, they're compiler directives.\n",[34,83,85],{"class":36,"line":84},5,[34,86,87],{"class":68},"\u002F\u002F The compiler transforms them into setup() return values.\n",[34,89,91],{"class":36,"line":90},6,[34,92,94],{"emptyLinePlaceholder":93},true,"\n",[34,96,98],{"class":36,"line":97},7,[34,99,100],{"class":68},"\u002F\u002F ── 1. defineProps — typed props via generic ──\n",[34,102,104,108,112,115,118],{"class":36,"line":103},8,[34,105,107],{"class":106},"svdQ7","const",[34,109,111],{"class":110},"snvgF"," props",[34,113,114],{"class":106}," =",[34,116,117],{"class":48}," defineProps",[34,119,120],{"class":40},"\u003C{\n",[34,122,124,128,131],{"class":36,"line":123},9,[34,125,127],{"class":126},"sCrzJ","  userId",[34,129,130],{"class":106},":",[34,132,133],{"class":110}," number\n",[34,135,137,140,143,146,149,152,154,157],{"class":36,"line":136},10,[34,138,139],{"class":126},"  role",[34,141,142],{"class":106},"?:",[34,144,145],{"class":58}," 'admin'",[34,147,148],{"class":106}," |",[34,150,151],{"class":58}," 'user'",[34,153,148],{"class":106},[34,155,156],{"class":58}," 'guest'",[34,158,159],{"class":68},"  \u002F\u002F optional union\n",[34,161,163,166,168,171],{"class":36,"line":162},11,[34,164,165],{"class":126},"  tags",[34,167,142],{"class":106},[34,169,170],{"class":110}," string",[34,172,173],{"class":40},"[]\n",[34,175,177],{"class":36,"line":176},12,[34,178,179],{"class":40},"}>()\n",[34,181,183],{"class":36,"line":182},13,[34,184,94],{"emptyLinePlaceholder":93},[34,186,188],{"class":36,"line":187},14,[34,189,190],{"class":68},"\u002F\u002F ── withDefaults: provide defaults for optional props (TS-only) ──\n",[34,192,194],{"class":36,"line":193},15,[34,195,196],{"class":68},"\u002F\u002F Required because TS interface defaults don't exist at runtime.\n",[34,198,200,202,205,208,210,212,215,218,220,223,225,228],{"class":36,"line":199},16,[34,201,107],{"class":106},[34,203,204],{"class":40}," { ",[34,206,207],{"class":110},"role",[34,209,114],{"class":106},[34,211,151],{"class":58},[34,213,214],{"class":40},", ",[34,216,217],{"class":110},"tags",[34,219,114],{"class":106},[34,221,222],{"class":40}," [] } ",[34,224,55],{"class":106},[34,226,227],{"class":48}," withDefaults",[34,229,230],{"class":40},"(props, {\n",[34,232,234,237,240],{"class":36,"line":233},17,[34,235,236],{"class":40},"  role: ",[34,238,239],{"class":58},"'user'",[34,241,242],{"class":40},",\n",[34,244,246,248,251,254,257],{"class":36,"line":245},18,[34,247,165],{"class":48},[34,249,250],{"class":40},": () ",[34,252,253],{"class":106},"=>",[34,255,256],{"class":40}," [],  ",[34,258,259],{"class":68},"\u002F\u002F factory function for non-primitive defaults (fresh per instance)\n",[34,261,263],{"class":36,"line":262},19,[34,264,265],{"class":40},"})\n",[34,267,269],{"class":36,"line":268},20,[34,270,94],{"emptyLinePlaceholder":93},[34,272,274],{"class":36,"line":273},21,[34,275,276],{"class":68},"\u002F\u002F ── 2. defineEmits — typed events ──\n",[34,278,280,282,285,287,290],{"class":36,"line":279},22,[34,281,107],{"class":106},[34,283,284],{"class":110}," emit",[34,286,114],{"class":106},[34,288,289],{"class":48}," defineEmits",[34,291,120],{"class":40},[34,293,295,298,301,303,306,308,311,313,316,319,321,324],{"class":36,"line":294},23,[34,296,297],{"class":40},"  (",[34,299,300],{"class":126},"e",[34,302,130],{"class":106},[34,304,305],{"class":58}," 'update'",[34,307,214],{"class":40},[34,309,310],{"class":126},"userId",[34,312,130],{"class":106},[34,314,315],{"class":110}," number",[34,317,318],{"class":40},")",[34,320,130],{"class":106},[34,322,323],{"class":110}," void",[34,325,326],{"class":68},"           \u002F\u002F named event with payload\n",[34,328,330,332,334,336,339,341,344,346,348,351,353,355,358,361,363,366,369,371],{"class":36,"line":329},24,[34,331,297],{"class":40},[34,333,300],{"class":126},[34,335,130],{"class":106},[34,337,338],{"class":58}," 'delete'",[34,340,214],{"class":40},[34,342,343],{"class":126},"payload",[34,345,130],{"class":106},[34,347,204],{"class":40},[34,349,350],{"class":126},"id",[34,352,130],{"class":106},[34,354,315],{"class":110},[34,356,357],{"class":40},"; ",[34,359,360],{"class":126},"soft",[34,362,130],{"class":106},[34,364,365],{"class":110}," boolean",[34,367,368],{"class":40}," })",[34,370,130],{"class":106},[34,372,373],{"class":110}," void\n",[34,375,377,379,381,383,386,388,390,392],{"class":36,"line":376},25,[34,378,297],{"class":40},[34,380,300],{"class":126},[34,382,130],{"class":106},[34,384,385],{"class":58}," 'cancel'",[34,387,318],{"class":40},[34,389,130],{"class":106},[34,391,323],{"class":110},[34,393,394],{"class":68},"                            \u002F\u002F event with no payload\n",[34,396,398],{"class":36,"line":397},26,[34,399,179],{"class":40},[34,401,403],{"class":36,"line":402},27,[34,404,94],{"emptyLinePlaceholder":93},[34,406,408],{"class":36,"line":407},28,[34,409,410],{"class":68},"\u002F\u002F ── 3. defineExpose — explicitly expose internals to parent via template refs ──\n",[34,412,414],{"class":36,"line":413},29,[34,415,416],{"class":68},"\u002F\u002F \u003Cscript setup> components are CLOSED by default — parent ref only gets the DOM.\n",[34,418,420],{"class":36,"line":419},30,[34,421,422],{"class":68},"\u002F\u002F defineExpose opens a controlled API surface.\n",[34,424,426,429,432,435,438],{"class":36,"line":425},31,[34,427,428],{"class":106},"function",[34,430,431],{"class":48}," save",[34,433,434],{"class":40},"() { ",[34,436,437],{"class":68},"\u002F* ... *\u002F",[34,439,440],{"class":40}," }\n",[34,442,444,446,449,451,453],{"class":36,"line":443},32,[34,445,428],{"class":106},[34,447,448],{"class":48}," reset",[34,450,434],{"class":40},[34,452,437],{"class":68},[34,454,440],{"class":40},[34,456,458,461],{"class":36,"line":457},33,[34,459,460],{"class":48},"defineExpose",[34,462,463],{"class":40},"({ save, reset })\n",[34,465,467],{"class":36,"line":466},34,[34,468,469],{"class":68},"\u002F\u002F Parent: const childRef = ref(); childRef.value?.save()\n",[34,471,473,476,478],{"class":36,"line":472},35,[34,474,475],{"class":40},"\u003C\u002F",[34,477,45],{"class":44},[34,479,62],{"class":40},[34,481,483],{"class":36,"line":482},36,[34,484,94],{"emptyLinePlaceholder":93},[34,486,488,490,493],{"class":36,"line":487},37,[34,489,41],{"class":40},[34,491,492],{"class":44},"template",[34,494,62],{"class":40},[34,496,498,501,504],{"class":36,"line":497},38,[34,499,500],{"class":40},"  \u003C",[34,502,503],{"class":44},"div",[34,505,62],{"class":40},[34,507,509,512,515,518,520],{"class":36,"line":508},39,[34,510,511],{"class":40},"    \u003C",[34,513,514],{"class":44},"p",[34,516,517],{"class":40},">User: {{ userId }}\u003C\u002F",[34,519,514],{"class":44},[34,521,62],{"class":40},[34,523,525,527,529,532,534],{"class":36,"line":524},40,[34,526,511],{"class":40},[34,528,514],{"class":44},[34,530,531],{"class":40},">Role: {{ role }}\u003C\u002F",[34,533,514],{"class":44},[34,535,62],{"class":40},[34,537,539,541,544,547,549,552,555,557],{"class":36,"line":538},41,[34,540,511],{"class":40},[34,542,543],{"class":44},"button",[34,545,546],{"class":48}," @click",[34,548,55],{"class":40},[34,550,551],{"class":58},"\"emit('update', userId)\"",[34,553,554],{"class":40},">Update\u003C\u002F",[34,556,543],{"class":44},[34,558,62],{"class":40},[34,560,562,565,567],{"class":36,"line":561},42,[34,563,564],{"class":40},"  \u003C\u002F",[34,566,503],{"class":44},[34,568,62],{"class":40},[34,570,572,574,576],{"class":36,"line":571},43,[34,573,475],{"class":40},[34,575,492],{"class":44},[34,577,62],{"class":40},[15,579,581],{"id":580},"prop-validation-and-default-factories","Prop Validation and Default Factories",[20,583,586],{"filename":584,"language":585},"prop-validation.js","javascript",[25,587,590],{"className":588,"code":589,"language":585,"meta":29,"style":29},"language-javascript shiki shiki-themes github-light github-dark","\u002F\u002F ── Runtime prop validation (Options API style, still works in \u003Cscript setup>) ──\n\u002F\u002F Use when you need runtime validation (not just TS types).\nconst props = defineProps({\n  \u002F\u002F type: constructor — Vue checks instanceof at runtime\n  userId: Number,                    \u002F\u002F must be a number\n\n  \u002F\u002F type + required + default\n  role: {\n    type: String,\n    required: false,\n    default: 'user',\n    \u002F\u002F validator runs AFTER type check; receives the raw value (not default)\n    validator: (v) => ['admin', 'user', 'guest'].includes(v),\n  },\n\n  \u002F\u002F ── Object\u002Farray defaults MUST be factory functions ──\n  \u002F\u002F ❌ WRONG: default: [] — shared by reference across all instances (like data() bug)\n  \u002F\u002F ✅ CORRECT: factory returns a fresh copy per instance\n  tags: {\n    type: Array,\n    default: () => [],               \u002F\u002F fresh array per instance\n  },\n\n  config: {\n    type: Object,\n    default: () => ({ theme: 'dark', lang: 'en' }),  \u002F\u002F fresh object per instance\n  },\n\n  \u002F\u002F ── Multiple types: type can be an array of constructors ──\n  id: [Number, String],              \u002F\u002F accepts 42 or \"42\"\n\n  \u002F\u002F ── Boolean has special casting rules ──\n  disabled: Boolean,\n  \u002F\u002F \u003CMyComp disabled \u002F>         → true (attribute present)\n  \u002F\u002F \u003CMyComp :disabled=\"false\" \u002F> → false (explicit binding)\n  \u002F\u002F \u003CMyComp \u002F>                  → false (absent, uses default if set)\n})\n",[31,591,592,597,602,615,620,628,632,637,642,647,657,666,671,711,716,720,725,730,735,740,745,760,764,768,773,778,804,808,812,817,825,829,834,839,844,849,854],{"__ignoreMap":29},[34,593,594],{"class":36,"line":37},[34,595,596],{"class":68},"\u002F\u002F ── Runtime prop validation (Options API style, still works in \u003Cscript setup>) ──\n",[34,598,599],{"class":36,"line":65},[34,600,601],{"class":68},"\u002F\u002F Use when you need runtime validation (not just TS types).\n",[34,603,604,606,608,610,612],{"class":36,"line":72},[34,605,107],{"class":106},[34,607,111],{"class":110},[34,609,114],{"class":106},[34,611,117],{"class":48},[34,613,614],{"class":40},"({\n",[34,616,617],{"class":36,"line":78},[34,618,619],{"class":68},"  \u002F\u002F type: constructor — Vue checks instanceof at runtime\n",[34,621,622,625],{"class":36,"line":84},[34,623,624],{"class":40},"  userId: Number,                    ",[34,626,627],{"class":68},"\u002F\u002F must be a number\n",[34,629,630],{"class":36,"line":90},[34,631,94],{"emptyLinePlaceholder":93},[34,633,634],{"class":36,"line":97},[34,635,636],{"class":68},"  \u002F\u002F type + required + default\n",[34,638,639],{"class":36,"line":103},[34,640,641],{"class":40},"  role: {\n",[34,643,644],{"class":36,"line":123},[34,645,646],{"class":40},"    type: String,\n",[34,648,649,652,655],{"class":36,"line":136},[34,650,651],{"class":40},"    required: ",[34,653,654],{"class":110},"false",[34,656,242],{"class":40},[34,658,659,662,664],{"class":36,"line":162},[34,660,661],{"class":40},"    default: ",[34,663,239],{"class":58},[34,665,242],{"class":40},[34,667,668],{"class":36,"line":176},[34,669,670],{"class":68},"    \u002F\u002F validator runs AFTER type check; receives the raw value (not default)\n",[34,672,673,676,679,682,685,687,690,693,695,697,699,702,705,708],{"class":36,"line":182},[34,674,675],{"class":48},"    validator",[34,677,678],{"class":40},": (",[34,680,681],{"class":126},"v",[34,683,684],{"class":40},") ",[34,686,253],{"class":106},[34,688,689],{"class":40}," [",[34,691,692],{"class":58},"'admin'",[34,694,214],{"class":40},[34,696,239],{"class":58},[34,698,214],{"class":40},[34,700,701],{"class":58},"'guest'",[34,703,704],{"class":40},"].",[34,706,707],{"class":48},"includes",[34,709,710],{"class":40},"(v),\n",[34,712,713],{"class":36,"line":187},[34,714,715],{"class":40},"  },\n",[34,717,718],{"class":36,"line":193},[34,719,94],{"emptyLinePlaceholder":93},[34,721,722],{"class":36,"line":199},[34,723,724],{"class":68},"  \u002F\u002F ── Object\u002Farray defaults MUST be factory functions ──\n",[34,726,727],{"class":36,"line":233},[34,728,729],{"class":68},"  \u002F\u002F ❌ WRONG: default: [] — shared by reference across all instances (like data() bug)\n",[34,731,732],{"class":36,"line":245},[34,733,734],{"class":68},"  \u002F\u002F ✅ CORRECT: factory returns a fresh copy per instance\n",[34,736,737],{"class":36,"line":262},[34,738,739],{"class":40},"  tags: {\n",[34,741,742],{"class":36,"line":268},[34,743,744],{"class":40},"    type: Array,\n",[34,746,747,750,752,754,757],{"class":36,"line":273},[34,748,749],{"class":48},"    default",[34,751,250],{"class":40},[34,753,253],{"class":106},[34,755,756],{"class":40}," [],               ",[34,758,759],{"class":68},"\u002F\u002F fresh array per instance\n",[34,761,762],{"class":36,"line":279},[34,763,715],{"class":40},[34,765,766],{"class":36,"line":294},[34,767,94],{"emptyLinePlaceholder":93},[34,769,770],{"class":36,"line":329},[34,771,772],{"class":40},"  config: {\n",[34,774,775],{"class":36,"line":376},[34,776,777],{"class":40},"    type: Object,\n",[34,779,780,782,784,786,789,792,795,798,801],{"class":36,"line":397},[34,781,749],{"class":48},[34,783,250],{"class":40},[34,785,253],{"class":106},[34,787,788],{"class":40}," ({ theme: ",[34,790,791],{"class":58},"'dark'",[34,793,794],{"class":40},", lang: ",[34,796,797],{"class":58},"'en'",[34,799,800],{"class":40}," }),  ",[34,802,803],{"class":68},"\u002F\u002F fresh object per instance\n",[34,805,806],{"class":36,"line":402},[34,807,715],{"class":40},[34,809,810],{"class":36,"line":407},[34,811,94],{"emptyLinePlaceholder":93},[34,813,814],{"class":36,"line":413},[34,815,816],{"class":68},"  \u002F\u002F ── Multiple types: type can be an array of constructors ──\n",[34,818,819,822],{"class":36,"line":419},[34,820,821],{"class":40},"  id: [Number, String],              ",[34,823,824],{"class":68},"\u002F\u002F accepts 42 or \"42\"\n",[34,826,827],{"class":36,"line":425},[34,828,94],{"emptyLinePlaceholder":93},[34,830,831],{"class":36,"line":443},[34,832,833],{"class":68},"  \u002F\u002F ── Boolean has special casting rules ──\n",[34,835,836],{"class":36,"line":457},[34,837,838],{"class":40},"  disabled: Boolean,\n",[34,840,841],{"class":36,"line":466},[34,842,843],{"class":68},"  \u002F\u002F \u003CMyComp disabled \u002F>         → true (attribute present)\n",[34,845,846],{"class":36,"line":472},[34,847,848],{"class":68},"  \u002F\u002F \u003CMyComp :disabled=\"false\" \u002F> → false (explicit binding)\n",[34,850,851],{"class":36,"line":482},[34,852,853],{"class":68},"  \u002F\u002F \u003CMyComp \u002F>                  → false (absent, uses default if set)\n",[34,855,856],{"class":36,"line":487},[34,857,265],{"class":40},[15,859,861],{"id":860},"attribute-fallthrough-attrs-on-fragments","Attribute Fallthrough — $attrs on Fragments",[20,863,865,970],{"filename":864,"language":23},"Fallthrough.vue",[25,866,868],{"className":27,"code":867,"language":23,"meta":29,"style":29},"\u003Cscript setup>\n\u002F\u002F ── $attrs: non-prop attributes passed from parent ──\n\u002F\u002F Includes: class, style, id, data-*, aria-*, custom attributes\n\u002F\u002F Excludes: props declared in defineProps, emits declared in defineEmits\n\n\u002F\u002F ── Single root node: $attrs auto-applied to the root element ──\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003C!-- Parent: \u003CMyInput class=\"big\" data-test=\"email\" placeholder=\"Email\" \u002F>\n       If `placeholder` is NOT a declared prop, it lands in $attrs.\n       Vue auto-applies $attrs to this \u003Cinput> (the single root). -->\n  \u003Cinput class=\"base-input\" \u002F>\n  \u003C!-- Result: \u003Cinput class=\"base-input big\" data-test=\"email\" placeholder=\"Email\" \u002F> -->\n\u003C\u002Ftemplate>\n",[31,869,870,880,885,890,895,899,904,912,916,924,929,934,939,957,962],{"__ignoreMap":29},[34,871,872,874,876,878],{"class":36,"line":37},[34,873,41],{"class":40},[34,875,45],{"class":44},[34,877,49],{"class":48},[34,879,62],{"class":40},[34,881,882],{"class":36,"line":65},[34,883,884],{"class":68},"\u002F\u002F ── $attrs: non-prop attributes passed from parent ──\n",[34,886,887],{"class":36,"line":72},[34,888,889],{"class":68},"\u002F\u002F Includes: class, style, id, data-*, aria-*, custom attributes\n",[34,891,892],{"class":36,"line":78},[34,893,894],{"class":68},"\u002F\u002F Excludes: props declared in defineProps, emits declared in defineEmits\n",[34,896,897],{"class":36,"line":84},[34,898,94],{"emptyLinePlaceholder":93},[34,900,901],{"class":36,"line":90},[34,902,903],{"class":68},"\u002F\u002F ── Single root node: $attrs auto-applied to the root element ──\n",[34,905,906,908,910],{"class":36,"line":97},[34,907,475],{"class":40},[34,909,45],{"class":44},[34,911,62],{"class":40},[34,913,914],{"class":36,"line":103},[34,915,94],{"emptyLinePlaceholder":93},[34,917,918,920,922],{"class":36,"line":123},[34,919,41],{"class":40},[34,921,492],{"class":44},[34,923,62],{"class":40},[34,925,926],{"class":36,"line":136},[34,927,928],{"class":68},"  \u003C!-- Parent: \u003CMyInput class=\"big\" data-test=\"email\" placeholder=\"Email\" \u002F>\n",[34,930,931],{"class":36,"line":162},[34,932,933],{"class":68},"       If `placeholder` is NOT a declared prop, it lands in $attrs.\n",[34,935,936],{"class":36,"line":176},[34,937,938],{"class":68},"       Vue auto-applies $attrs to this \u003Cinput> (the single root). -->\n",[34,940,941,943,946,949,951,954],{"class":36,"line":182},[34,942,500],{"class":40},[34,944,945],{"class":44},"input",[34,947,948],{"class":48}," class",[34,950,55],{"class":40},[34,952,953],{"class":58},"\"base-input\"",[34,955,956],{"class":40}," \u002F>\n",[34,958,959],{"class":36,"line":187},[34,960,961],{"class":68},"  \u003C!-- Result: \u003Cinput class=\"base-input big\" data-test=\"email\" placeholder=\"Email\" \u002F> -->\n",[34,963,964,966,968],{"class":36,"line":193},[34,965,475],{"class":40},[34,967,492],{"class":44},[34,969,62],{"class":40},[20,971,973,1136],{"filename":972,"language":23},"FragmentFallthrough.vue",[25,974,976],{"className":27,"code":975,"language":23,"meta":29,"style":29},"\u003Cscript setup>\nimport { useAttrs } from 'vue'\nconst attrs = useAttrs()  \u002F\u002F access $attrs in script (equivalent to $attrs in template)\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003C!-- ── Fragment (multiple roots): $attrs does NOT auto-apply ── -->\n  \u003C!-- Vue can't know which root to put attrs on → must bind manually -->\n  \u003Cdiv class=\"wrapper\">\n    \u003Clabel>{{ attrs.label || 'Input' }}\u003C\u002Flabel>\n    \u003C!-- Explicitly forward $attrs to the input -->\n    \u003Cinput v-bind=\"$attrs\" class=\"base-input\" \u002F>\n  \u003C\u002Fdiv>\n\n  \u003C!-- ── Disable inheritance entirely with inheritAttrs: false ── -->\n  \u003C!-- Useful when you want full control over where attrs go -->\n\u003C\u002Ftemplate>\n",[31,977,978,988,1002,1020,1028,1032,1040,1045,1050,1065,1079,1084,1106,1114,1118,1123,1128],{"__ignoreMap":29},[34,979,980,982,984,986],{"class":36,"line":37},[34,981,41],{"class":40},[34,983,45],{"class":44},[34,985,49],{"class":48},[34,987,62],{"class":40},[34,989,990,993,996,999],{"class":36,"line":65},[34,991,992],{"class":106},"import",[34,994,995],{"class":40}," { useAttrs } ",[34,997,998],{"class":106},"from",[34,1000,1001],{"class":58}," 'vue'\n",[34,1003,1004,1006,1009,1011,1014,1017],{"class":36,"line":72},[34,1005,107],{"class":106},[34,1007,1008],{"class":110}," attrs",[34,1010,114],{"class":106},[34,1012,1013],{"class":48}," useAttrs",[34,1015,1016],{"class":40},"()  ",[34,1018,1019],{"class":68},"\u002F\u002F access $attrs in script (equivalent to $attrs in template)\n",[34,1021,1022,1024,1026],{"class":36,"line":78},[34,1023,475],{"class":40},[34,1025,45],{"class":44},[34,1027,62],{"class":40},[34,1029,1030],{"class":36,"line":84},[34,1031,94],{"emptyLinePlaceholder":93},[34,1033,1034,1036,1038],{"class":36,"line":90},[34,1035,41],{"class":40},[34,1037,492],{"class":44},[34,1039,62],{"class":40},[34,1041,1042],{"class":36,"line":97},[34,1043,1044],{"class":68},"  \u003C!-- ── Fragment (multiple roots): $attrs does NOT auto-apply ── -->\n",[34,1046,1047],{"class":36,"line":103},[34,1048,1049],{"class":68},"  \u003C!-- Vue can't know which root to put attrs on → must bind manually -->\n",[34,1051,1052,1054,1056,1058,1060,1063],{"class":36,"line":123},[34,1053,500],{"class":40},[34,1055,503],{"class":44},[34,1057,948],{"class":48},[34,1059,55],{"class":40},[34,1061,1062],{"class":58},"\"wrapper\"",[34,1064,62],{"class":40},[34,1066,1067,1069,1072,1075,1077],{"class":36,"line":136},[34,1068,511],{"class":40},[34,1070,1071],{"class":44},"label",[34,1073,1074],{"class":40},">{{ attrs.label || 'Input' }}\u003C\u002F",[34,1076,1071],{"class":44},[34,1078,62],{"class":40},[34,1080,1081],{"class":36,"line":162},[34,1082,1083],{"class":68},"    \u003C!-- Explicitly forward $attrs to the input -->\n",[34,1085,1086,1088,1090,1093,1095,1098,1100,1102,1104],{"class":36,"line":176},[34,1087,511],{"class":40},[34,1089,945],{"class":44},[34,1091,1092],{"class":48}," v-bind",[34,1094,55],{"class":40},[34,1096,1097],{"class":58},"\"$attrs\"",[34,1099,948],{"class":48},[34,1101,55],{"class":40},[34,1103,953],{"class":58},[34,1105,956],{"class":40},[34,1107,1108,1110,1112],{"class":36,"line":182},[34,1109,564],{"class":40},[34,1111,503],{"class":44},[34,1113,62],{"class":40},[34,1115,1116],{"class":36,"line":187},[34,1117,94],{"emptyLinePlaceholder":93},[34,1119,1120],{"class":36,"line":193},[34,1121,1122],{"class":68},"  \u003C!-- ── Disable inheritance entirely with inheritAttrs: false ── -->\n",[34,1124,1125],{"class":36,"line":199},[34,1126,1127],{"class":68},"  \u003C!-- Useful when you want full control over where attrs go -->\n",[34,1129,1130,1132,1134],{"class":36,"line":233},[34,1131,475],{"class":40},[34,1133,492],{"class":44},[34,1135,62],{"class":40},[20,1137,1139],{"filename":1138,"language":23},"NoInherit.vue",[25,1140,1142],{"className":27,"code":1141,"language":23,"meta":29,"style":29},"\u003Cscript setup>\n\u002F\u002F ── inheritAttrs: false — disable auto-fallthrough ──\n\u002F\u002F $attrs still exists in the object, just not auto-applied to root.\ndefineOptions({ inheritAttrs: false })\n\u002F\u002F Now the parent's class\u002Fstyle\u002Fdata-* go NOWHERE unless you bind $attrs explicitly.\n\u002F\u002F Useful: wrapper components that split attrs across multiple children.\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv class=\"outer\">\n    \u003Cinput v-bind=\"$attrs\" \u002F>  \u003C!-- only the input gets parent attrs -->\n    \u003Cspan class=\"hint\">{{ $attrs.hint }}\u003C\u002Fspan>  \u003C!-- read individual attr -->\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[31,1143,1144,1154,1159,1164,1177,1182,1187,1195,1199,1207,1222,1240,1264,1272],{"__ignoreMap":29},[34,1145,1146,1148,1150,1152],{"class":36,"line":37},[34,1147,41],{"class":40},[34,1149,45],{"class":44},[34,1151,49],{"class":48},[34,1153,62],{"class":40},[34,1155,1156],{"class":36,"line":65},[34,1157,1158],{"class":68},"\u002F\u002F ── inheritAttrs: false — disable auto-fallthrough ──\n",[34,1160,1161],{"class":36,"line":72},[34,1162,1163],{"class":68},"\u002F\u002F $attrs still exists in the object, just not auto-applied to root.\n",[34,1165,1166,1169,1172,1174],{"class":36,"line":78},[34,1167,1168],{"class":48},"defineOptions",[34,1170,1171],{"class":40},"({ inheritAttrs: ",[34,1173,654],{"class":110},[34,1175,1176],{"class":40}," })\n",[34,1178,1179],{"class":36,"line":84},[34,1180,1181],{"class":68},"\u002F\u002F Now the parent's class\u002Fstyle\u002Fdata-* go NOWHERE unless you bind $attrs explicitly.\n",[34,1183,1184],{"class":36,"line":90},[34,1185,1186],{"class":68},"\u002F\u002F Useful: wrapper components that split attrs across multiple children.\n",[34,1188,1189,1191,1193],{"class":36,"line":97},[34,1190,475],{"class":40},[34,1192,45],{"class":44},[34,1194,62],{"class":40},[34,1196,1197],{"class":36,"line":103},[34,1198,94],{"emptyLinePlaceholder":93},[34,1200,1201,1203,1205],{"class":36,"line":123},[34,1202,41],{"class":40},[34,1204,492],{"class":44},[34,1206,62],{"class":40},[34,1208,1209,1211,1213,1215,1217,1220],{"class":36,"line":136},[34,1210,500],{"class":40},[34,1212,503],{"class":44},[34,1214,948],{"class":48},[34,1216,55],{"class":40},[34,1218,1219],{"class":58},"\"outer\"",[34,1221,62],{"class":40},[34,1223,1224,1226,1228,1230,1232,1234,1237],{"class":36,"line":162},[34,1225,511],{"class":40},[34,1227,945],{"class":44},[34,1229,1092],{"class":48},[34,1231,55],{"class":40},[34,1233,1097],{"class":58},[34,1235,1236],{"class":40}," \u002F>  ",[34,1238,1239],{"class":68},"\u003C!-- only the input gets parent attrs -->\n",[34,1241,1242,1244,1246,1248,1250,1253,1256,1258,1261],{"class":36,"line":176},[34,1243,511],{"class":40},[34,1245,34],{"class":44},[34,1247,948],{"class":48},[34,1249,55],{"class":40},[34,1251,1252],{"class":58},"\"hint\"",[34,1254,1255],{"class":40},">{{ $attrs.hint }}\u003C\u002F",[34,1257,34],{"class":44},[34,1259,1260],{"class":40},">  ",[34,1262,1263],{"class":68},"\u003C!-- read individual attr -->\n",[34,1265,1266,1268,1270],{"class":36,"line":182},[34,1267,564],{"class":40},[34,1269,503],{"class":44},[34,1271,62],{"class":40},[34,1273,1274,1276,1278],{"class":36,"line":187},[34,1275,475],{"class":40},[34,1277,492],{"class":44},[34,1279,62],{"class":40},[15,1281,1283,1284,1287],{"id":1282},"dynamic-components-with-keepalive-caching","Dynamic Components — ",[1285,1286],"is",{}," with KeepAlive Caching",[20,1289,1291],{"filename":1290,"language":23},"DynamicTabs.vue",[25,1292,1294],{"className":27,"code":1293,"language":23,"meta":29,"style":29},"\u003Cscript setup>\nimport { ref, shallowRef, markRaw, defineAsyncComponent } from 'vue'\nimport Overview from '.\u002FOverview.vue'\nimport Settings from '.\u002FSettings.vue'\n\n\u002F\u002F ── shallowRef for component refs — avoid deep reactivity on component objects ──\n\u002F\u002F Components are complex objects with internal state — reactive() wrapping them\n\u002F\u002F is wasteful and can break internal Vue mechanisms. Use shallowRef or markRaw.\nconst tabs = shallowRef({\n  overview: markRaw(Overview),\n  settings: markRaw(Settings),\n  \u002F\u002F ── Async component: loaded on demand, code-split into separate chunk ──\n  reports: defineAsyncComponent(() => import('.\u002FReports.vue')),\n})\n\nconst activeTab = ref('overview')\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003C!-- :is binds to a component definition (object, string name, or async) -->\n  \u003C!-- KeepAlive caches the component instance when it's toggled out →\n       state (form inputs, scroll position) preserved on return -->\n  \u003CKeepAlive :max=\"3\">\n    \u003Ccomponent :is=\"tabs[activeTab]\" \u002F>\n  \u003C\u002FKeepAlive>\n  \u003C!-- :max=\"3\": LRU cache — keeps last 3 instances, destroys older ones -->\n\n  \u003Cbutton v-for=\"(comp, name) in tabs\" :key=\"name\" @click=\"activeTab = name\">\n    {{ name }}\n  \u003C\u002Fbutton>\n\u003C\u002Ftemplate>\n",[31,1295,1296,1306,1317,1329,1341,1345,1350,1355,1360,1374,1385,1395,1400,1425,1429,1433,1453,1461,1465,1473,1478,1483,1488,1513,1530,1538,1543,1547,1578,1583,1591],{"__ignoreMap":29},[34,1297,1298,1300,1302,1304],{"class":36,"line":37},[34,1299,41],{"class":40},[34,1301,45],{"class":44},[34,1303,49],{"class":48},[34,1305,62],{"class":40},[34,1307,1308,1310,1313,1315],{"class":36,"line":65},[34,1309,992],{"class":106},[34,1311,1312],{"class":40}," { ref, shallowRef, markRaw, defineAsyncComponent } ",[34,1314,998],{"class":106},[34,1316,1001],{"class":58},[34,1318,1319,1321,1324,1326],{"class":36,"line":72},[34,1320,992],{"class":106},[34,1322,1323],{"class":40}," Overview ",[34,1325,998],{"class":106},[34,1327,1328],{"class":58}," '.\u002FOverview.vue'\n",[34,1330,1331,1333,1336,1338],{"class":36,"line":78},[34,1332,992],{"class":106},[34,1334,1335],{"class":40}," Settings ",[34,1337,998],{"class":106},[34,1339,1340],{"class":58}," '.\u002FSettings.vue'\n",[34,1342,1343],{"class":36,"line":84},[34,1344,94],{"emptyLinePlaceholder":93},[34,1346,1347],{"class":36,"line":90},[34,1348,1349],{"class":68},"\u002F\u002F ── shallowRef for component refs — avoid deep reactivity on component objects ──\n",[34,1351,1352],{"class":36,"line":97},[34,1353,1354],{"class":68},"\u002F\u002F Components are complex objects with internal state — reactive() wrapping them\n",[34,1356,1357],{"class":36,"line":103},[34,1358,1359],{"class":68},"\u002F\u002F is wasteful and can break internal Vue mechanisms. Use shallowRef or markRaw.\n",[34,1361,1362,1364,1367,1369,1372],{"class":36,"line":123},[34,1363,107],{"class":106},[34,1365,1366],{"class":110}," tabs",[34,1368,114],{"class":106},[34,1370,1371],{"class":48}," shallowRef",[34,1373,614],{"class":40},[34,1375,1376,1379,1382],{"class":36,"line":136},[34,1377,1378],{"class":40},"  overview: ",[34,1380,1381],{"class":48},"markRaw",[34,1383,1384],{"class":40},"(Overview),\n",[34,1386,1387,1390,1392],{"class":36,"line":162},[34,1388,1389],{"class":40},"  settings: ",[34,1391,1381],{"class":48},[34,1393,1394],{"class":40},"(Settings),\n",[34,1396,1397],{"class":36,"line":176},[34,1398,1399],{"class":68},"  \u002F\u002F ── Async component: loaded on demand, code-split into separate chunk ──\n",[34,1401,1402,1405,1408,1411,1413,1416,1419,1422],{"class":36,"line":182},[34,1403,1404],{"class":40},"  reports: ",[34,1406,1407],{"class":48},"defineAsyncComponent",[34,1409,1410],{"class":40},"(() ",[34,1412,253],{"class":106},[34,1414,1415],{"class":106}," import",[34,1417,1418],{"class":40},"(",[34,1420,1421],{"class":58},"'.\u002FReports.vue'",[34,1423,1424],{"class":40},")),\n",[34,1426,1427],{"class":36,"line":187},[34,1428,265],{"class":40},[34,1430,1431],{"class":36,"line":193},[34,1432,94],{"emptyLinePlaceholder":93},[34,1434,1435,1437,1440,1442,1445,1447,1450],{"class":36,"line":199},[34,1436,107],{"class":106},[34,1438,1439],{"class":110}," activeTab",[34,1441,114],{"class":106},[34,1443,1444],{"class":48}," ref",[34,1446,1418],{"class":40},[34,1448,1449],{"class":58},"'overview'",[34,1451,1452],{"class":40},")\n",[34,1454,1455,1457,1459],{"class":36,"line":233},[34,1456,475],{"class":40},[34,1458,45],{"class":44},[34,1460,62],{"class":40},[34,1462,1463],{"class":36,"line":245},[34,1464,94],{"emptyLinePlaceholder":93},[34,1466,1467,1469,1471],{"class":36,"line":262},[34,1468,41],{"class":40},[34,1470,492],{"class":44},[34,1472,62],{"class":40},[34,1474,1475],{"class":36,"line":268},[34,1476,1477],{"class":68},"  \u003C!-- :is binds to a component definition (object, string name, or async) -->\n",[34,1479,1480],{"class":36,"line":273},[34,1481,1482],{"class":68},"  \u003C!-- KeepAlive caches the component instance when it's toggled out →\n",[34,1484,1485],{"class":36,"line":279},[34,1486,1487],{"class":68},"       state (form inputs, scroll position) preserved on return -->\n",[34,1489,1490,1492,1495,1498,1501,1503,1506,1509,1511],{"class":36,"line":294},[34,1491,500],{"class":40},[34,1493,1494],{"class":44},"KeepAlive",[34,1496,1497],{"class":40}," :",[34,1499,1500],{"class":48},"max",[34,1502,55],{"class":40},[34,1504,1505],{"class":58},"\"",[34,1507,1508],{"class":110},"3",[34,1510,1505],{"class":58},[34,1512,62],{"class":40},[34,1514,1515,1517,1520,1523,1525,1528],{"class":36,"line":329},[34,1516,511],{"class":40},[34,1518,1519],{"class":44},"component",[34,1521,1522],{"class":48}," :is",[34,1524,55],{"class":40},[34,1526,1527],{"class":58},"\"tabs[activeTab]\"",[34,1529,956],{"class":40},[34,1531,1532,1534,1536],{"class":36,"line":376},[34,1533,564],{"class":40},[34,1535,1494],{"class":44},[34,1537,62],{"class":40},[34,1539,1540],{"class":36,"line":397},[34,1541,1542],{"class":68},"  \u003C!-- :max=\"3\": LRU cache — keeps last 3 instances, destroys older ones -->\n",[34,1544,1545],{"class":36,"line":402},[34,1546,94],{"emptyLinePlaceholder":93},[34,1548,1549,1551,1553,1556,1558,1561,1564,1566,1569,1571,1573,1576],{"class":36,"line":407},[34,1550,500],{"class":40},[34,1552,543],{"class":44},[34,1554,1555],{"class":48}," v-for",[34,1557,55],{"class":40},[34,1559,1560],{"class":58},"\"(comp, name) in tabs\"",[34,1562,1563],{"class":48}," :key",[34,1565,55],{"class":40},[34,1567,1568],{"class":58},"\"name\"",[34,1570,546],{"class":48},[34,1572,55],{"class":40},[34,1574,1575],{"class":58},"\"activeTab = name\"",[34,1577,62],{"class":40},[34,1579,1580],{"class":36,"line":413},[34,1581,1582],{"class":40},"    {{ name }}\n",[34,1584,1585,1587,1589],{"class":36,"line":419},[34,1586,564],{"class":40},[34,1588,543],{"class":44},[34,1590,62],{"class":40},[34,1592,1593,1595,1597],{"class":36,"line":425},[34,1594,475],{"class":40},[34,1596,492],{"class":44},[34,1598,62],{"class":40},[15,1600,1602],{"id":1601},"component-v-model-the-contract","Component v-model — The Contract",[20,1604,1606,1803,1956,1960,2204,2208,2338,2342,2345,2463],{"filename":1605,"language":23},"CustomInput.vue",[25,1607,1609],{"className":27,"code":1608,"language":23,"meta":29,"style":29},"\u003Cscript setup>\n\u002F\u002F ── v-model on a component expands to: ──\n\u002F\u002F   :modelValue=\"value\" @update:modelValue=\"value = $event\"\n\u002F\u002F Vue 3 renamed: value→modelValue, input→update:modelValue (breaking from Vue 2)\n\ndefineProps\u003C{\n  modelValue: string  \u002F\u002F the bound value\n}>()\n\nconst emit = defineEmits\u003C{\n  (e: 'update:modelValue', value: string): void  \u002F\u002F must emit this to update\n}>()\n\nfunction onInput(e) {\n  emit('update:modelValue', e.target.value)  \u002F\u002F notify parent of new value\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cinput :value=\"modelValue\" @input=\"onInput\" \u002F>\n\u003C\u002Ftemplate>\n",[31,1610,1611,1621,1626,1631,1636,1640,1647,1659,1663,1667,1679,1708,1712,1716,1730,1746,1751,1759,1763,1771,1795],{"__ignoreMap":29},[34,1612,1613,1615,1617,1619],{"class":36,"line":37},[34,1614,41],{"class":40},[34,1616,45],{"class":44},[34,1618,49],{"class":48},[34,1620,62],{"class":40},[34,1622,1623],{"class":36,"line":65},[34,1624,1625],{"class":68},"\u002F\u002F ── v-model on a component expands to: ──\n",[34,1627,1628],{"class":36,"line":72},[34,1629,1630],{"class":68},"\u002F\u002F   :modelValue=\"value\" @update:modelValue=\"value = $event\"\n",[34,1632,1633],{"class":36,"line":78},[34,1634,1635],{"class":68},"\u002F\u002F Vue 3 renamed: value→modelValue, input→update:modelValue (breaking from Vue 2)\n",[34,1637,1638],{"class":36,"line":84},[34,1639,94],{"emptyLinePlaceholder":93},[34,1641,1642,1645],{"class":36,"line":90},[34,1643,1644],{"class":48},"defineProps",[34,1646,120],{"class":40},[34,1648,1649,1652,1654,1656],{"class":36,"line":97},[34,1650,1651],{"class":126},"  modelValue",[34,1653,130],{"class":106},[34,1655,170],{"class":110},[34,1657,1658],{"class":68},"  \u002F\u002F the bound value\n",[34,1660,1661],{"class":36,"line":103},[34,1662,179],{"class":40},[34,1664,1665],{"class":36,"line":123},[34,1666,94],{"emptyLinePlaceholder":93},[34,1668,1669,1671,1673,1675,1677],{"class":36,"line":136},[34,1670,107],{"class":106},[34,1672,284],{"class":110},[34,1674,114],{"class":106},[34,1676,289],{"class":48},[34,1678,120],{"class":40},[34,1680,1681,1683,1685,1687,1690,1692,1695,1697,1699,1701,1703,1705],{"class":36,"line":162},[34,1682,297],{"class":40},[34,1684,300],{"class":126},[34,1686,130],{"class":106},[34,1688,1689],{"class":58}," 'update:modelValue'",[34,1691,214],{"class":40},[34,1693,1694],{"class":126},"value",[34,1696,130],{"class":106},[34,1698,170],{"class":110},[34,1700,318],{"class":40},[34,1702,130],{"class":106},[34,1704,323],{"class":110},[34,1706,1707],{"class":68},"  \u002F\u002F must emit this to update\n",[34,1709,1710],{"class":36,"line":176},[34,1711,179],{"class":40},[34,1713,1714],{"class":36,"line":182},[34,1715,94],{"emptyLinePlaceholder":93},[34,1717,1718,1720,1723,1725,1727],{"class":36,"line":187},[34,1719,428],{"class":106},[34,1721,1722],{"class":48}," onInput",[34,1724,1418],{"class":40},[34,1726,300],{"class":126},[34,1728,1729],{"class":40},") {\n",[34,1731,1732,1735,1737,1740,1743],{"class":36,"line":193},[34,1733,1734],{"class":48},"  emit",[34,1736,1418],{"class":40},[34,1738,1739],{"class":58},"'update:modelValue'",[34,1741,1742],{"class":40},", e.target.value)  ",[34,1744,1745],{"class":68},"\u002F\u002F notify parent of new value\n",[34,1747,1748],{"class":36,"line":199},[34,1749,1750],{"class":40},"}\n",[34,1752,1753,1755,1757],{"class":36,"line":233},[34,1754,475],{"class":40},[34,1756,45],{"class":44},[34,1758,62],{"class":40},[34,1760,1761],{"class":36,"line":245},[34,1762,94],{"emptyLinePlaceholder":93},[34,1764,1765,1767,1769],{"class":36,"line":262},[34,1766,41],{"class":40},[34,1768,492],{"class":44},[34,1770,62],{"class":40},[34,1772,1773,1775,1777,1780,1782,1785,1788,1790,1793],{"class":36,"line":268},[34,1774,500],{"class":40},[34,1776,945],{"class":44},[34,1778,1779],{"class":48}," :value",[34,1781,55],{"class":40},[34,1783,1784],{"class":58},"\"modelValue\"",[34,1786,1787],{"class":48}," @input",[34,1789,55],{"class":40},[34,1791,1792],{"class":58},"\"onInput\"",[34,1794,956],{"class":40},[34,1796,1797,1799,1801],{"class":36,"line":273},[34,1798,475],{"class":40},[34,1800,492],{"class":44},[34,1802,62],{"class":40},[20,1804,1806],{"filename":1805,"language":23},"MultiVModel.vue",[25,1807,1809],{"className":27,"code":1808,"language":23,"meta":29,"style":29},"\u003Cscript setup>\n\u002F\u002F ── Multiple v-models on one component ──\n\u002F\u002F Parent: \u003CUserForm v-model:firstName=\"fn\" v-model:lastName=\"ln\" \u002F>\ndefineProps\u003C{\n  firstName: string\n  lastName: string\n}>()\nconst emit = defineEmits(['update:firstName', 'update:lastName'])\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cinput :value=\"firstName\" @input=\"emit('update:firstName', $event.target.value)\" \u002F>\n  \u003Cinput :value=\"lastName\" @input=\"emit('update:lastName', $event.target.value)\" \u002F>\n\u003C\u002Ftemplate>\n",[31,1810,1811,1821,1826,1831,1837,1847,1856,1860,1884,1892,1896,1904,1926,1948],{"__ignoreMap":29},[34,1812,1813,1815,1817,1819],{"class":36,"line":37},[34,1814,41],{"class":40},[34,1816,45],{"class":44},[34,1818,49],{"class":48},[34,1820,62],{"class":40},[34,1822,1823],{"class":36,"line":65},[34,1824,1825],{"class":68},"\u002F\u002F ── Multiple v-models on one component ──\n",[34,1827,1828],{"class":36,"line":72},[34,1829,1830],{"class":68},"\u002F\u002F Parent: \u003CUserForm v-model:firstName=\"fn\" v-model:lastName=\"ln\" \u002F>\n",[34,1832,1833,1835],{"class":36,"line":78},[34,1834,1644],{"class":48},[34,1836,120],{"class":40},[34,1838,1839,1842,1844],{"class":36,"line":84},[34,1840,1841],{"class":126},"  firstName",[34,1843,130],{"class":106},[34,1845,1846],{"class":110}," string\n",[34,1848,1849,1852,1854],{"class":36,"line":90},[34,1850,1851],{"class":126},"  lastName",[34,1853,130],{"class":106},[34,1855,1846],{"class":110},[34,1857,1858],{"class":36,"line":97},[34,1859,179],{"class":40},[34,1861,1862,1864,1866,1868,1870,1873,1876,1878,1881],{"class":36,"line":103},[34,1863,107],{"class":106},[34,1865,284],{"class":110},[34,1867,114],{"class":106},[34,1869,289],{"class":48},[34,1871,1872],{"class":40},"([",[34,1874,1875],{"class":58},"'update:firstName'",[34,1877,214],{"class":40},[34,1879,1880],{"class":58},"'update:lastName'",[34,1882,1883],{"class":40},"])\n",[34,1885,1886,1888,1890],{"class":36,"line":123},[34,1887,475],{"class":40},[34,1889,45],{"class":44},[34,1891,62],{"class":40},[34,1893,1894],{"class":36,"line":136},[34,1895,94],{"emptyLinePlaceholder":93},[34,1897,1898,1900,1902],{"class":36,"line":162},[34,1899,41],{"class":40},[34,1901,492],{"class":44},[34,1903,62],{"class":40},[34,1905,1906,1908,1910,1912,1914,1917,1919,1921,1924],{"class":36,"line":176},[34,1907,500],{"class":40},[34,1909,945],{"class":44},[34,1911,1779],{"class":48},[34,1913,55],{"class":40},[34,1915,1916],{"class":58},"\"firstName\"",[34,1918,1787],{"class":48},[34,1920,55],{"class":40},[34,1922,1923],{"class":58},"\"emit('update:firstName', $event.target.value)\"",[34,1925,956],{"class":40},[34,1927,1928,1930,1932,1934,1936,1939,1941,1943,1946],{"class":36,"line":182},[34,1929,500],{"class":40},[34,1931,945],{"class":44},[34,1933,1779],{"class":48},[34,1935,55],{"class":40},[34,1937,1938],{"class":58},"\"lastName\"",[34,1940,1787],{"class":48},[34,1942,55],{"class":40},[34,1944,1945],{"class":58},"\"emit('update:lastName', $event.target.value)\"",[34,1947,956],{"class":40},[34,1949,1950,1952,1954],{"class":36,"line":187},[34,1951,475],{"class":40},[34,1953,492],{"class":44},[34,1955,62],{"class":40},[15,1957,1959],{"id":1958},"tips-tricks","💡 Tips & Tricks",[20,1961,1963],{"filename":1962,"language":23},"TipsTricks.vue",[25,1964,1966],{"className":27,"code":1965,"language":23,"meta":29,"style":29},"\u003Cscript setup>\nimport { ref, useTemplateRef, defineAsyncComponent } from 'vue'\n\n\u002F\u002F ── 1. useTemplateRef (3.5+) — typed template ref without ref(null) boilerplate ──\nconst inputEl = useTemplateRef\u003CHTMLInputElement>('inputEl')\n\u002F\u002F Template: \u003Cinput ref=\"inputEl\" \u002F> — inputEl.value is HTMLInputElement | null\n\n\u002F\u002F ── 2. Async component with loading\u002Ferror states ──\nconst AsyncChart = defineAsyncComponent({\n  loader: () => import('.\u002FChart.vue'),\n  loadingComponent: LoadingSpinner,\n  errorComponent: ErrorDisplay,\n  delay: 200,       \u002F\u002F show loading after 200ms (avoid flicker for fast loads)\n  timeout: 8000,    \u002F\u002F show error after 8s\n  \u002F\u002F suspensible: true → works with \u003CSuspense> (defer to nearest boundary)\n})\n\n\u002F\u002F ── 3. defineOptions — set Options API options inside script setup ──\ndefineOptions({\n  name: 'UserCard',        \u002F\u002F named for DevTools + keep-alive include\u002Fexclude\n  inheritAttrs: false,\n})\n\n\u002F\u002F ── 4. defineModel (3.4+) — declarative v-model without boilerplate ──\nconst model = defineModel\u003Cstring>()  \u002F\u002F auto-creates modelValue prop + emit\n\u002F\u002F \u003Cinput v-model=\"model\" \u002F> — writes go through the parent binding automatically\n\u003C\u002Fscript>\n",[31,1967,1968,1978,1989,1993,1998,2023,2028,2032,2037,2051,2070,2075,2080,2094,2108,2113,2117,2121,2126,2132,2146,2155,2159,2163,2168,2191,2196],{"__ignoreMap":29},[34,1969,1970,1972,1974,1976],{"class":36,"line":37},[34,1971,41],{"class":40},[34,1973,45],{"class":44},[34,1975,49],{"class":48},[34,1977,62],{"class":40},[34,1979,1980,1982,1985,1987],{"class":36,"line":65},[34,1981,992],{"class":106},[34,1983,1984],{"class":40}," { ref, useTemplateRef, defineAsyncComponent } ",[34,1986,998],{"class":106},[34,1988,1001],{"class":58},[34,1990,1991],{"class":36,"line":72},[34,1992,94],{"emptyLinePlaceholder":93},[34,1994,1995],{"class":36,"line":78},[34,1996,1997],{"class":68},"\u002F\u002F ── 1. useTemplateRef (3.5+) — typed template ref without ref(null) boilerplate ──\n",[34,1999,2000,2002,2005,2007,2010,2012,2015,2018,2021],{"class":36,"line":84},[34,2001,107],{"class":106},[34,2003,2004],{"class":110}," inputEl",[34,2006,114],{"class":106},[34,2008,2009],{"class":48}," useTemplateRef",[34,2011,41],{"class":40},[34,2013,2014],{"class":48},"HTMLInputElement",[34,2016,2017],{"class":40},">(",[34,2019,2020],{"class":58},"'inputEl'",[34,2022,1452],{"class":40},[34,2024,2025],{"class":36,"line":90},[34,2026,2027],{"class":68},"\u002F\u002F Template: \u003Cinput ref=\"inputEl\" \u002F> — inputEl.value is HTMLInputElement | null\n",[34,2029,2030],{"class":36,"line":97},[34,2031,94],{"emptyLinePlaceholder":93},[34,2033,2034],{"class":36,"line":103},[34,2035,2036],{"class":68},"\u002F\u002F ── 2. Async component with loading\u002Ferror states ──\n",[34,2038,2039,2041,2044,2046,2049],{"class":36,"line":123},[34,2040,107],{"class":106},[34,2042,2043],{"class":110}," AsyncChart",[34,2045,114],{"class":106},[34,2047,2048],{"class":48}," defineAsyncComponent",[34,2050,614],{"class":40},[34,2052,2053,2056,2058,2060,2062,2064,2067],{"class":36,"line":136},[34,2054,2055],{"class":48},"  loader",[34,2057,250],{"class":40},[34,2059,253],{"class":106},[34,2061,1415],{"class":106},[34,2063,1418],{"class":40},[34,2065,2066],{"class":58},"'.\u002FChart.vue'",[34,2068,2069],{"class":40},"),\n",[34,2071,2072],{"class":36,"line":162},[34,2073,2074],{"class":40},"  loadingComponent: LoadingSpinner,\n",[34,2076,2077],{"class":36,"line":176},[34,2078,2079],{"class":40},"  errorComponent: ErrorDisplay,\n",[34,2081,2082,2085,2088,2091],{"class":36,"line":182},[34,2083,2084],{"class":40},"  delay: ",[34,2086,2087],{"class":110},"200",[34,2089,2090],{"class":40},",       ",[34,2092,2093],{"class":68},"\u002F\u002F show loading after 200ms (avoid flicker for fast loads)\n",[34,2095,2096,2099,2102,2105],{"class":36,"line":187},[34,2097,2098],{"class":40},"  timeout: ",[34,2100,2101],{"class":110},"8000",[34,2103,2104],{"class":40},",    ",[34,2106,2107],{"class":68},"\u002F\u002F show error after 8s\n",[34,2109,2110],{"class":36,"line":193},[34,2111,2112],{"class":68},"  \u002F\u002F suspensible: true → works with \u003CSuspense> (defer to nearest boundary)\n",[34,2114,2115],{"class":36,"line":199},[34,2116,265],{"class":40},[34,2118,2119],{"class":36,"line":233},[34,2120,94],{"emptyLinePlaceholder":93},[34,2122,2123],{"class":36,"line":245},[34,2124,2125],{"class":68},"\u002F\u002F ── 3. defineOptions — set Options API options inside script setup ──\n",[34,2127,2128,2130],{"class":36,"line":262},[34,2129,1168],{"class":48},[34,2131,614],{"class":40},[34,2133,2134,2137,2140,2143],{"class":36,"line":268},[34,2135,2136],{"class":40},"  name: ",[34,2138,2139],{"class":58},"'UserCard'",[34,2141,2142],{"class":40},",        ",[34,2144,2145],{"class":68},"\u002F\u002F named for DevTools + keep-alive include\u002Fexclude\n",[34,2147,2148,2151,2153],{"class":36,"line":273},[34,2149,2150],{"class":40},"  inheritAttrs: ",[34,2152,654],{"class":110},[34,2154,242],{"class":40},[34,2156,2157],{"class":36,"line":279},[34,2158,265],{"class":40},[34,2160,2161],{"class":36,"line":294},[34,2162,94],{"emptyLinePlaceholder":93},[34,2164,2165],{"class":36,"line":329},[34,2166,2167],{"class":68},"\u002F\u002F ── 4. defineModel (3.4+) — declarative v-model without boilerplate ──\n",[34,2169,2170,2172,2175,2177,2180,2182,2185,2188],{"class":36,"line":376},[34,2171,107],{"class":106},[34,2173,2174],{"class":110}," model",[34,2176,114],{"class":106},[34,2178,2179],{"class":48}," defineModel",[34,2181,41],{"class":40},[34,2183,2184],{"class":110},"string",[34,2186,2187],{"class":40},">()  ",[34,2189,2190],{"class":68},"\u002F\u002F auto-creates modelValue prop + emit\n",[34,2192,2193],{"class":36,"line":397},[34,2194,2195],{"class":68},"\u002F\u002F \u003Cinput v-model=\"model\" \u002F> — writes go through the parent binding automatically\n",[34,2197,2198,2200,2202],{"class":36,"line":402},[34,2199,475],{"class":40},[34,2201,45],{"class":44},[34,2203,62],{"class":40},[15,2205,2207],{"id":2206},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[20,2209,2212],{"filename":2210,"language":2211},"edge-cases.ts","typescript",[25,2213,2216],{"className":2214,"code":2215,"language":2211,"meta":29,"style":29},"language-typescript shiki shiki-themes github-light github-dark","\u002F\u002F ── 1. Object\u002Farray prop defaults must be factory functions ──\n\u002F\u002F default: [] or default: {} → shared across ALL instances (reference bug)\n\u002F\u002F default: () => [] or () => ({}) → fresh copy per instance (correct)\n\n\u002F\u002F ── 2. Boolean prop casting — empty string is NOT false ──\n\u002F\u002F \u003CComp disabled \u002F>    → disabled = true (attribute present = true)\n\u002F\u002F \u003CComp disabled=\"\" \u002F> → disabled = true (empty string still means present)\n\u002F\u002F \u003CComp :disabled=\"false\" \u002F> → disabled = false (explicit boolean binding)\n\n\u002F\u002F ── 3. defineProps is a compile-time macro — can't be inside functions ──\n\u002F\u002F ❌ function setup() { const props = defineProps() } — only works in \u003Cscript setup> top level\n\u002F\u002F ✅ const props = defineProps() — must be top-level in \u003Cscript setup>\n\n\u002F\u002F ── 4. defineExpose is opt-in — \u003Cscript setup> is closed by default ──\n\u002F\u002F Parent template refs on a \u003Cscript setup> child get null for everything\n\u002F\u002F unless the child calls defineExpose(). Options API exposes all data\u002Fmethods.\n\n\u002F\u002F ── 5. Async components need shallowRef\u002FmarkRaw, not reactive ──\n\u002F\u002F reactive() on a component definition breaks internal Vue compilation caches.\n\u002F\u002F Store component refs in shallowRef or markRaw them before assignment.\n\n\u002F\u002F ── 6. Prop type checks are dev-only — stripped in production ──\n\u002F\u002F defineProps\u003C{ x: number }>() → pure TS, zero runtime check in prod.\n\u002F\u002F defineProps({ x: Number }) → runtime instanceof check, dev warning only.\n\u002F\u002F Always validate at the boundary if type safety is critical in production.\n",[31,2217,2218,2223,2228,2233,2237,2242,2247,2252,2257,2261,2266,2271,2276,2280,2285,2290,2295,2299,2304,2309,2314,2318,2323,2328,2333],{"__ignoreMap":29},[34,2219,2220],{"class":36,"line":37},[34,2221,2222],{"class":68},"\u002F\u002F ── 1. Object\u002Farray prop defaults must be factory functions ──\n",[34,2224,2225],{"class":36,"line":65},[34,2226,2227],{"class":68},"\u002F\u002F default: [] or default: {} → shared across ALL instances (reference bug)\n",[34,2229,2230],{"class":36,"line":72},[34,2231,2232],{"class":68},"\u002F\u002F default: () => [] or () => ({}) → fresh copy per instance (correct)\n",[34,2234,2235],{"class":36,"line":78},[34,2236,94],{"emptyLinePlaceholder":93},[34,2238,2239],{"class":36,"line":84},[34,2240,2241],{"class":68},"\u002F\u002F ── 2. Boolean prop casting — empty string is NOT false ──\n",[34,2243,2244],{"class":36,"line":90},[34,2245,2246],{"class":68},"\u002F\u002F \u003CComp disabled \u002F>    → disabled = true (attribute present = true)\n",[34,2248,2249],{"class":36,"line":97},[34,2250,2251],{"class":68},"\u002F\u002F \u003CComp disabled=\"\" \u002F> → disabled = true (empty string still means present)\n",[34,2253,2254],{"class":36,"line":103},[34,2255,2256],{"class":68},"\u002F\u002F \u003CComp :disabled=\"false\" \u002F> → disabled = false (explicit boolean binding)\n",[34,2258,2259],{"class":36,"line":123},[34,2260,94],{"emptyLinePlaceholder":93},[34,2262,2263],{"class":36,"line":136},[34,2264,2265],{"class":68},"\u002F\u002F ── 3. defineProps is a compile-time macro — can't be inside functions ──\n",[34,2267,2268],{"class":36,"line":162},[34,2269,2270],{"class":68},"\u002F\u002F ❌ function setup() { const props = defineProps() } — only works in \u003Cscript setup> top level\n",[34,2272,2273],{"class":36,"line":176},[34,2274,2275],{"class":68},"\u002F\u002F ✅ const props = defineProps() — must be top-level in \u003Cscript setup>\n",[34,2277,2278],{"class":36,"line":182},[34,2279,94],{"emptyLinePlaceholder":93},[34,2281,2282],{"class":36,"line":187},[34,2283,2284],{"class":68},"\u002F\u002F ── 4. defineExpose is opt-in — \u003Cscript setup> is closed by default ──\n",[34,2286,2287],{"class":36,"line":193},[34,2288,2289],{"class":68},"\u002F\u002F Parent template refs on a \u003Cscript setup> child get null for everything\n",[34,2291,2292],{"class":36,"line":199},[34,2293,2294],{"class":68},"\u002F\u002F unless the child calls defineExpose(). Options API exposes all data\u002Fmethods.\n",[34,2296,2297],{"class":36,"line":233},[34,2298,94],{"emptyLinePlaceholder":93},[34,2300,2301],{"class":36,"line":245},[34,2302,2303],{"class":68},"\u002F\u002F ── 5. Async components need shallowRef\u002FmarkRaw, not reactive ──\n",[34,2305,2306],{"class":36,"line":262},[34,2307,2308],{"class":68},"\u002F\u002F reactive() on a component definition breaks internal Vue compilation caches.\n",[34,2310,2311],{"class":36,"line":268},[34,2312,2313],{"class":68},"\u002F\u002F Store component refs in shallowRef or markRaw them before assignment.\n",[34,2315,2316],{"class":36,"line":273},[34,2317,94],{"emptyLinePlaceholder":93},[34,2319,2320],{"class":36,"line":279},[34,2321,2322],{"class":68},"\u002F\u002F ── 6. Prop type checks are dev-only — stripped in production ──\n",[34,2324,2325],{"class":36,"line":294},[34,2326,2327],{"class":68},"\u002F\u002F defineProps\u003C{ x: number }>() → pure TS, zero runtime check in prod.\n",[34,2329,2330],{"class":36,"line":329},[34,2331,2332],{"class":68},"\u002F\u002F defineProps({ x: Number }) → runtime instanceof check, dev warning only.\n",[34,2334,2335],{"class":36,"line":376},[34,2336,2337],{"class":68},"\u002F\u002F Always validate at the boundary if type safety is critical in production.\n",[15,2339,2341],{"id":2340},"spot-the-bug","🧠 Spot the Bug",[514,2343,2344],{},"A custom checkbox component always shows the same checked state across all instances.",[20,2346,2348],{"filename":2347,"language":23},"CheckboxBug.vue",[25,2349,2351],{"className":27,"code":2350,"language":23,"meta":29,"style":29},"\u003Cscript setup>\ndefineProps({\n  checked: {\n    type: Array,\n    default: [],  \u002F\u002F ← shared reference across all instances\n  },\n})\nconst emit = defineEmits(['update:checked'])\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cinput type=\"checkbox\" :checked=\"checked.includes('x')\" \u002F>\n\u003C\u002Ftemplate>\n",[31,2352,2353,2363,2369,2374,2378,2386,2390,2394,2411,2419,2423,2431,2455],{"__ignoreMap":29},[34,2354,2355,2357,2359,2361],{"class":36,"line":37},[34,2356,41],{"class":40},[34,2358,45],{"class":44},[34,2360,49],{"class":48},[34,2362,62],{"class":40},[34,2364,2365,2367],{"class":36,"line":65},[34,2366,1644],{"class":48},[34,2368,614],{"class":40},[34,2370,2371],{"class":36,"line":72},[34,2372,2373],{"class":40},"  checked: {\n",[34,2375,2376],{"class":36,"line":78},[34,2377,744],{"class":40},[34,2379,2380,2383],{"class":36,"line":84},[34,2381,2382],{"class":40},"    default: [],  ",[34,2384,2385],{"class":68},"\u002F\u002F ← shared reference across all instances\n",[34,2387,2388],{"class":36,"line":90},[34,2389,715],{"class":40},[34,2391,2392],{"class":36,"line":97},[34,2393,265],{"class":40},[34,2395,2396,2398,2400,2402,2404,2406,2409],{"class":36,"line":103},[34,2397,107],{"class":106},[34,2399,284],{"class":110},[34,2401,114],{"class":106},[34,2403,289],{"class":48},[34,2405,1872],{"class":40},[34,2407,2408],{"class":58},"'update:checked'",[34,2410,1883],{"class":40},[34,2412,2413,2415,2417],{"class":36,"line":123},[34,2414,475],{"class":40},[34,2416,45],{"class":44},[34,2418,62],{"class":40},[34,2420,2421],{"class":36,"line":136},[34,2422,94],{"emptyLinePlaceholder":93},[34,2424,2425,2427,2429],{"class":36,"line":162},[34,2426,41],{"class":40},[34,2428,492],{"class":44},[34,2430,62],{"class":40},[34,2432,2433,2435,2437,2440,2442,2445,2448,2450,2453],{"class":36,"line":176},[34,2434,500],{"class":40},[34,2436,945],{"class":44},[34,2438,2439],{"class":48}," type",[34,2441,55],{"class":40},[34,2443,2444],{"class":58},"\"checkbox\"",[34,2446,2447],{"class":48}," :checked",[34,2449,55],{"class":40},[34,2451,2452],{"class":58},"\"checked.includes('x')\"",[34,2454,956],{"class":40},[34,2456,2457,2459,2461],{"class":36,"line":182},[34,2458,475],{"class":40},[34,2460,492],{"class":44},[34,2462,62],{"class":40},[2464,2465,2466,2470,2476,2483,2526],"details",{},[2467,2468,2469],"summary",{},"Answer",[514,2471,2472,2475],{},[31,2473,2474],{},"default: []"," creates one array at module evaluation time and shares it across every component instance that uses the default. When one instance pushes to it, all others see the mutation.",[514,2477,2478,2482],{},[2479,2480,2481],"strong",{},"Fix"," — use a factory function:",[20,2484,2486],{"filename":2485,"language":585},"checkbox-fix.js",[25,2487,2489],{"className":588,"code":2488,"language":585,"meta":29,"style":29},"defineProps({\n  checked: {\n    type: Array,\n    default: () => [],  \u002F\u002F fresh array per instance — no shared reference\n  },\n})\n",[31,2490,2491,2497,2501,2505,2518,2522],{"__ignoreMap":29},[34,2492,2493,2495],{"class":36,"line":37},[34,2494,1644],{"class":48},[34,2496,614],{"class":40},[34,2498,2499],{"class":36,"line":65},[34,2500,2373],{"class":40},[34,2502,2503],{"class":36,"line":72},[34,2504,744],{"class":40},[34,2506,2507,2509,2511,2513,2515],{"class":36,"line":78},[34,2508,749],{"class":48},[34,2510,250],{"class":40},[34,2512,253],{"class":106},[34,2514,256],{"class":40},[34,2516,2517],{"class":68},"\u002F\u002F fresh array per instance — no shared reference\n",[34,2519,2520],{"class":36,"line":84},[34,2521,715],{"class":40},[34,2523,2524],{"class":36,"line":90},[34,2525,265],{"class":40},[514,2527,2528,2531,2532,2535],{},[2479,2529,2530],{},"The lesson",": object\u002Farray prop defaults must be factory functions returning a fresh copy. Static defaults share one reference across all instances, causing cross-instance state leaks identical to the Vue 2 ",[31,2533,2534],{},"data: {}"," bug.",[2537,2538,2539],"style",{},"html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sk71V, html code.shiki .sk71V{--shiki-default:#22863A;--shiki-github-dark:#85E89D}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}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 .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}",{"title":29,"searchDepth":65,"depth":65,"links":2541},[2542,2543,2544,2545,2547,2548,2549,2550],{"id":17,"depth":65,"text":18},{"id":580,"depth":65,"text":581},{"id":860,"depth":65,"text":861},{"id":1282,"depth":65,"text":2546},"Dynamic Components —  with KeepAlive Caching",{"id":1601,"depth":65,"text":1602},{"id":1958,"depth":65,"text":1959},{"id":2206,"depth":65,"text":2207},{"id":2340,"depth":65,"text":2341},"SFC compilation pipeline, defineProps\u002FdefineEmits\u002FdefineExpose macros, prop validation, single-root vs fragment attr fallthrough, async component registration, and component v-model contracts.","md",{},"\u002Fvue\u002F05-components-basics",{"title":5,"description":2551},"vue\u002F05-components-basics","VH_DI3HZsVFjZ2ao5nWBVWTBGc0YGeU3j9TBLTK_1YU",1789924655441]