[{"data":1,"prerenderedAt":1009},["ShallowReactive",2],{"guide-pascalcase-component-naming":3},{"id":4,"title":5,"body":6,"date":1001,"description":1002,"extension":1003,"meta":1004,"navigation":136,"path":1005,"readingTime":158,"seo":1006,"stem":1007,"__hash__":1008},"guides\u002Fguides\u002Fpascalcase-component-naming.md","PascalCase for Component Naming",{"type":7,"value":8,"toc":978},"minimark",[9,14,37,44,48,53,61,95,177,187,191,194,292,295,299,427,431,434,471,474,478,482,592,596,683,687,697,724,782,786,790,800,804,824,828,838,842,845,920,924,945,949,965,974],[10,11,13],"h2",{"id":12},"why-pascalcase-for-components","Why PascalCase for Components",[15,16,17,18,22,23,22,26,29,30,22,33,36],"p",{},"Vue and React both mandate PascalCase for component names. This isn't arbitrary — it solves a real ambiguity problem. In HTML, lowercase tags are reserved for native elements (",[19,20,21],"code",{},"\u003Cdiv>",", ",[19,24,25],{},"\u003Cspan>",[19,27,28],{},"\u003Cbutton>","). PascalCase names (",[19,31,32],{},"\u003CUserProfile>",[19,34,35],{},"\u003CSearchBar>",") immediately distinguish custom components from native elements.",[15,38,39,40,43],{},"Without this convention, ",[19,41,42],{},"\u003Cuserprofile>"," could be a custom component or an unknown HTML element. The browser treats unknown lowercase tags as inline elements, which leads to subtle rendering bugs. PascalCase eliminates the ambiguity entirely.",[10,45,47],{"id":46},"framework-rules","Framework Rules",[49,50,52],"h3",{"id":51},"vue","Vue",[15,54,55,56,60],{},"Vue's style guide lists PascalCase component names as ",[57,58,59],"strong",{},"essential"," (the strongest category). The rules:",[62,63,64,74,85],"ul",{},[65,66,67,68,22,71],"li",{},"Component files: ",[19,69,70],{},"UserProfile.vue",[19,72,73],{},"SearchBar.vue",[65,75,76,77,80,81,84],{},"In templates: ",[19,78,79],{},"\u003CUserProfile \u002F>"," or ",[19,82,83],{},"\u003Cuser-profile \u002F>"," (both work, but PascalCase is preferred)",[65,86,87,88,91,92],{},"In ",[19,89,90],{},"components"," registration: ",[19,93,94],{},"UserProfile",[96,97,102],"pre",{"className":98,"code":99,"language":100,"meta":101,"style":101},"language-javascript shiki shiki-themes github-light github-dark","\u002F\u002F Component registration\nimport UserProfile from '.\u002FUserProfile.vue'\n\nexport default {\n  components: {\n    UserProfile  \u002F\u002F PascalCase key\n  }\n}\n","javascript","",[19,103,104,113,131,138,150,156,165,171],{"__ignoreMap":101},[105,106,109],"span",{"class":107,"line":108},"line",1,[105,110,112],{"class":111},"sJ8bj","\u002F\u002F Component registration\n",[105,114,116,120,124,127],{"class":107,"line":115},2,[105,117,119],{"class":118},"szBVR","import",[105,121,123],{"class":122},"sVt8B"," UserProfile ",[105,125,126],{"class":118},"from",[105,128,130],{"class":129},"sZZnC"," '.\u002FUserProfile.vue'\n",[105,132,134],{"class":107,"line":133},3,[105,135,137],{"emptyLinePlaceholder":136},true,"\n",[105,139,141,144,147],{"class":107,"line":140},4,[105,142,143],{"class":118},"export",[105,145,146],{"class":118}," default",[105,148,149],{"class":122}," {\n",[105,151,153],{"class":107,"line":152},5,[105,154,155],{"class":122},"  components: {\n",[105,157,159,162],{"class":107,"line":158},6,[105,160,161],{"class":122},"    UserProfile  ",[105,163,164],{"class":111},"\u002F\u002F PascalCase key\n",[105,166,168],{"class":107,"line":167},7,[105,169,170],{"class":122},"  }\n",[105,172,174],{"class":107,"line":173},8,[105,175,176],{"class":122},"}\n",[15,178,179,180,183,184,186],{},"Vue auto-imports in Nuxt follow the same rule: ",[19,181,182],{},"components\u002FUserProfile.vue"," becomes ",[19,185,32],{},".",[49,188,190],{"id":189},"react","React",[15,192,193],{},"React requires PascalCase more strictly — lowercase component names render as native HTML elements:",[96,195,199],{"className":196,"code":197,"language":198,"meta":101,"style":101},"language-jsx shiki shiki-themes github-light github-dark","\u002F\u002F This renders a \u003Cuserprofile> HTML element — NOT your component\nfunction userprofile() { return \u003Cdiv>Hello\u003C\u002Fdiv> }\n\u003Cuserprofile \u002F>  \u002F\u002F BUG: renders unknown HTML element\n\n\u002F\u002F This renders your React component correctly\nfunction UserProfile() { return \u003Cdiv>Hello\u003C\u002Fdiv> }\n\u003CUserProfile \u002F>  \u002F\u002F Correct\n","jsx",[19,200,201,206,236,250,254,259,280],{"__ignoreMap":101},[105,202,203],{"class":107,"line":108},[105,204,205],{"class":111},"\u002F\u002F This renders a \u003Cuserprofile> HTML element — NOT your component\n",[105,207,208,211,215,218,221,224,228,231,233],{"class":107,"line":115},[105,209,210],{"class":118},"function",[105,212,214],{"class":213},"sScJk"," userprofile",[105,216,217],{"class":122},"() { ",[105,219,220],{"class":118},"return",[105,222,223],{"class":122}," \u003C",[105,225,227],{"class":226},"s9eBZ","div",[105,229,230],{"class":122},">Hello\u003C\u002F",[105,232,227],{"class":226},[105,234,235],{"class":122},"> }\n",[105,237,238,241,244,247],{"class":107,"line":133},[105,239,240],{"class":122},"\u003C",[105,242,243],{"class":226},"userprofile",[105,245,246],{"class":122}," \u002F>  ",[105,248,249],{"class":111},"\u002F\u002F BUG: renders unknown HTML element\n",[105,251,252],{"class":107,"line":140},[105,253,137],{"emptyLinePlaceholder":136},[105,255,256],{"class":107,"line":152},[105,257,258],{"class":111},"\u002F\u002F This renders your React component correctly\n",[105,260,261,263,266,268,270,272,274,276,278],{"class":107,"line":158},[105,262,210],{"class":118},[105,264,265],{"class":213}," UserProfile",[105,267,217],{"class":122},[105,269,220],{"class":118},[105,271,223],{"class":122},[105,273,227],{"class":226},[105,275,230],{"class":122},[105,277,227],{"class":226},[105,279,235],{"class":122},[105,281,282,284,287,289],{"class":107,"line":167},[105,283,240],{"class":122},[105,285,94],{"class":286},"sj4cs",[105,288,246],{"class":122},[105,290,291],{"class":111},"\u002F\u002F Correct\n",[15,293,294],{},"This distinction is enforced at the JSX level. React's JSX transform treats lowercase tags as strings (native elements) and PascalCase tags as component references.",[10,296,298],{"id":297},"naming-patterns-by-component-type","Naming Patterns by Component Type",[300,301,302,318],"table",{},[303,304,305],"thead",{},[306,307,308,312,315],"tr",{},[309,310,311],"th",{},"Component Type",[309,313,314],{},"PascalCase Example",[309,316,317],{},"File Name",[319,320,321,337,352,367,382,397,412],"tbody",{},[306,322,323,327,332],{},[324,325,326],"td",{},"Page section",[324,328,329],{},[19,330,331],{},"HeroSection",[324,333,334],{},[19,335,336],{},"HeroSection.vue",[306,338,339,342,347],{},[324,340,341],{},"UI primitive",[324,343,344],{},[19,345,346],{},"BaseButton",[324,348,349],{},[19,350,351],{},"BaseButton.vue",[306,353,354,357,362],{},[324,355,356],{},"Layout",[324,358,359],{},[19,360,361],{},"AppHeader",[324,363,364],{},[19,365,366],{},"AppHeader.vue",[306,368,369,372,377],{},[324,370,371],{},"Form",[324,373,374],{},[19,375,376],{},"LoginForm",[324,378,379],{},[19,380,381],{},"LoginForm.vue",[306,383,384,387,392],{},[324,385,386],{},"List item",[324,388,389],{},[19,390,391],{},"ProductCard",[324,393,394],{},[19,395,396],{},"ProductCard.vue",[306,398,399,402,407],{},[324,400,401],{},"Modal\u002Fdialog",[324,403,404],{},[19,405,406],{},"ConfirmDialog",[324,408,409],{},[19,410,411],{},"ConfirmDialog.vue",[306,413,414,417,422],{},[324,415,416],{},"Utility",[324,418,419],{},[19,420,421],{},"AnimatedCounter",[324,423,424],{},[19,425,426],{},"AnimatedCounter.vue",[49,428,430],{"id":429},"prefix-conventions","Prefix Conventions",[15,432,433],{},"Many teams add prefixes to signal component categories:",[62,435,436,448,459],{},[65,437,438,441,442,22,444,447],{},[57,439,440],{},"Base",": ",[19,443,346],{},[19,445,446],{},"BaseInput"," — reusable primitives",[65,449,450,441,453,22,455,458],{},[57,451,452],{},"App",[19,454,361],{},[19,456,457],{},"AppSidebar"," — application layout components",[65,460,461,441,464,22,467,470],{},[57,462,463],{},"The",[19,465,466],{},"TheNavigation",[19,468,469],{},"TheFooter"," — singleton components (one per page)",[15,472,473],{},"These prefixes are optional but help organize large component libraries.",[10,475,477],{"id":476},"enforcing-pascalcase","Enforcing PascalCase",[49,479,481],{"id":480},"eslint-for-vue","ESLint for Vue",[96,483,485],{"className":98,"code":484,"language":100,"meta":101,"style":101},"\u002F\u002F eslint.config.js\nimport vuePlugin from 'eslint-plugin-vue'\n\nexport default [\n  ...vuePlugin.configs['flat\u002Frecommended'],\n  {\n    rules: {\n      'vue\u002Fcomponent-definition-name-casing': ['error', 'PascalCase'],\n      'vue\u002Fcomponent-name-in-template-casing': ['error', 'PascalCase'],\n    }\n  }\n]\n",[19,486,487,492,504,508,517,531,536,541,559,575,581,586],{"__ignoreMap":101},[105,488,489],{"class":107,"line":108},[105,490,491],{"class":111},"\u002F\u002F eslint.config.js\n",[105,493,494,496,499,501],{"class":107,"line":115},[105,495,119],{"class":118},[105,497,498],{"class":122}," vuePlugin ",[105,500,126],{"class":118},[105,502,503],{"class":129}," 'eslint-plugin-vue'\n",[105,505,506],{"class":107,"line":133},[105,507,137],{"emptyLinePlaceholder":136},[105,509,510,512,514],{"class":107,"line":140},[105,511,143],{"class":118},[105,513,146],{"class":118},[105,515,516],{"class":122}," [\n",[105,518,519,522,525,528],{"class":107,"line":152},[105,520,521],{"class":118},"  ...",[105,523,524],{"class":122},"vuePlugin.configs[",[105,526,527],{"class":129},"'flat\u002Frecommended'",[105,529,530],{"class":122},"],\n",[105,532,533],{"class":107,"line":158},[105,534,535],{"class":122},"  {\n",[105,537,538],{"class":107,"line":167},[105,539,540],{"class":122},"    rules: {\n",[105,542,543,546,549,552,554,557],{"class":107,"line":173},[105,544,545],{"class":129},"      'vue\u002Fcomponent-definition-name-casing'",[105,547,548],{"class":122},": [",[105,550,551],{"class":129},"'error'",[105,553,22],{"class":122},[105,555,556],{"class":129},"'PascalCase'",[105,558,530],{"class":122},[105,560,562,565,567,569,571,573],{"class":107,"line":561},9,[105,563,564],{"class":129},"      'vue\u002Fcomponent-name-in-template-casing'",[105,566,548],{"class":122},[105,568,551],{"class":129},[105,570,22],{"class":122},[105,572,556],{"class":129},[105,574,530],{"class":122},[105,576,578],{"class":107,"line":577},10,[105,579,580],{"class":122},"    }\n",[105,582,584],{"class":107,"line":583},11,[105,585,170],{"class":122},[105,587,589],{"class":107,"line":588},12,[105,590,591],{"class":122},"]\n",[49,593,595],{"id":594},"eslint-for-react","ESLint for React",[96,597,599],{"className":98,"code":598,"language":100,"meta":101,"style":101},"\u002F\u002F eslint.config.js\nimport reactPlugin from 'eslint-plugin-react'\n\nexport default [\n  {\n    rules: {\n      'react\u002Fjsx-pascal-case': ['error', {\n        allowAllCaps: false,\n        ignore: [],\n      }]\n    }\n  }\n]\n",[19,600,601,605,617,621,629,633,637,649,660,665,670,674,678],{"__ignoreMap":101},[105,602,603],{"class":107,"line":108},[105,604,491],{"class":111},[105,606,607,609,612,614],{"class":107,"line":115},[105,608,119],{"class":118},[105,610,611],{"class":122}," reactPlugin ",[105,613,126],{"class":118},[105,615,616],{"class":129}," 'eslint-plugin-react'\n",[105,618,619],{"class":107,"line":133},[105,620,137],{"emptyLinePlaceholder":136},[105,622,623,625,627],{"class":107,"line":140},[105,624,143],{"class":118},[105,626,146],{"class":118},[105,628,516],{"class":122},[105,630,631],{"class":107,"line":152},[105,632,535],{"class":122},[105,634,635],{"class":107,"line":158},[105,636,540],{"class":122},[105,638,639,642,644,646],{"class":107,"line":167},[105,640,641],{"class":129},"      'react\u002Fjsx-pascal-case'",[105,643,548],{"class":122},[105,645,551],{"class":129},[105,647,648],{"class":122},", {\n",[105,650,651,654,657],{"class":107,"line":173},[105,652,653],{"class":122},"        allowAllCaps: ",[105,655,656],{"class":286},"false",[105,658,659],{"class":122},",\n",[105,661,662],{"class":107,"line":561},[105,663,664],{"class":122},"        ignore: [],\n",[105,666,667],{"class":107,"line":577},[105,668,669],{"class":122},"      }]\n",[105,671,672],{"class":107,"line":583},[105,673,580],{"class":122},[105,675,676],{"class":107,"line":588},[105,677,170],{"class":122},[105,679,681],{"class":107,"line":680},13,[105,682,591],{"class":122},[49,684,686],{"id":685},"nuxt-auto-import-naming","Nuxt Auto-Import Naming",[15,688,689,690,183,693,696],{},"Nuxt generates component names from file paths. ",[19,691,692],{},"components\u002Ftools\u002FJsonFormatter.vue",[19,694,695],{},"ToolsJsonFormatter",". To keep names clean:",[62,698,699,708,717],{},[65,700,701,702,705,706],{},"Use flat directories for frequent components: ",[19,703,704],{},"components\u002FSearchBar.vue"," → ",[19,707,35],{},[65,709,710,711,705,714],{},"Use nested directories for grouping: ",[19,712,713],{},"components\u002Fadmin\u002FUserTable.vue",[19,715,716],{},"\u003CAdminUserTable>",[65,718,719,720,723],{},"Configure path prefixes in ",[19,721,722],{},"nuxt.config.ts"," if needed",[96,725,729],{"className":726,"code":727,"language":728,"meta":101,"style":101},"language-typescript shiki shiki-themes github-light github-dark","\u002F\u002F nuxt.config.ts\nexport default defineNuxtConfig({\n  components: [\n    { path: '~\u002Fcomponents', pathPrefix: false },  \u002F\u002F Flat naming regardless of directory\n  ]\n})\n","typescript",[19,730,731,736,748,753,772,777],{"__ignoreMap":101},[105,732,733],{"class":107,"line":108},[105,734,735],{"class":111},"\u002F\u002F nuxt.config.ts\n",[105,737,738,740,742,745],{"class":107,"line":115},[105,739,143],{"class":118},[105,741,146],{"class":118},[105,743,744],{"class":213}," defineNuxtConfig",[105,746,747],{"class":122},"({\n",[105,749,750],{"class":107,"line":133},[105,751,752],{"class":122},"  components: [\n",[105,754,755,758,761,764,766,769],{"class":107,"line":140},[105,756,757],{"class":122},"    { path: ",[105,759,760],{"class":129},"'~\u002Fcomponents'",[105,762,763],{"class":122},", pathPrefix: ",[105,765,656],{"class":286},[105,767,768],{"class":122}," },  ",[105,770,771],{"class":111},"\u002F\u002F Flat naming regardless of directory\n",[105,773,774],{"class":107,"line":152},[105,775,776],{"class":122},"  ]\n",[105,778,779],{"class":107,"line":158},[105,780,781],{"class":122},"})\n",[10,783,785],{"id":784},"common-mistakes","Common Mistakes",[49,787,789],{"id":788},"_1-abbreviated-names","1. Abbreviated Names",[15,791,792,793,80,796,799],{},"Avoid ",[19,794,795],{},"UsrPrfl",[19,797,798],{},"BtnGrp",". Component names should be descriptive. The extra characters cost nothing in terms of performance, but cryptic names cost a lot in readability.",[49,801,803],{"id":802},"_2-single-word-names","2. Single-Word Names",[15,805,806,22,809,22,812,815,816,22,818,22,821,186],{},[19,807,808],{},"Button.vue",[19,810,811],{},"Form.vue",[19,813,814],{},"Table.vue"," — these collide with native HTML elements and third-party libraries. Prefix them: ",[19,817,346],{},[19,819,820],{},"ContactForm",[19,822,823],{},"DataTable",[49,825,827],{"id":826},"_3-inconsistent-casing-in-templates","3. Inconsistent Casing in Templates",[15,829,830,831,833,834,837],{},"Mixing ",[19,832,32],{}," and ",[19,835,836],{},"\u003Cuser-profile>"," in the same project confuses readers. Pick one and enforce it with ESLint.",[49,839,841],{"id":840},"_4-prop-names-in-pascalcase","4. Prop Names in PascalCase",[15,843,844],{},"Props should use camelCase in JavaScript and kebab-case in templates — never PascalCase:",[96,846,850],{"className":847,"code":848,"language":849,"meta":101,"style":101},"language-html shiki shiki-themes github-light github-dark","\u003C!-- Bad -->\n\u003CUserProfile UserName=\"john\" \u002F>\n\n\u003C!-- Good -->\n\u003CUserProfile userName=\"john\" \u002F>\n\u003C!-- or in templates: -->\n\u003CUserProfile user-name=\"john\" \u002F>\n","html",[19,851,852,857,876,880,885,900,905],{"__ignoreMap":101},[105,853,854],{"class":107,"line":108},[105,855,856],{"class":111},"\u003C!-- Bad -->\n",[105,858,859,861,864,867,870,873],{"class":107,"line":115},[105,860,240],{"class":122},[105,862,94],{"class":863},"s7hpK",[105,865,866],{"class":213}," UserName",[105,868,869],{"class":122},"=",[105,871,872],{"class":129},"\"john\"",[105,874,875],{"class":122}," \u002F>\n",[105,877,878],{"class":107,"line":133},[105,879,137],{"emptyLinePlaceholder":136},[105,881,882],{"class":107,"line":140},[105,883,884],{"class":111},"\u003C!-- Good -->\n",[105,886,887,889,891,894,896,898],{"class":107,"line":152},[105,888,240],{"class":122},[105,890,94],{"class":863},[105,892,893],{"class":213}," userName",[105,895,869],{"class":122},[105,897,872],{"class":129},[105,899,875],{"class":122},[105,901,902],{"class":107,"line":158},[105,903,904],{"class":111},"\u003C!-- or in templates: -->\n",[105,906,907,909,911,914,916,918],{"class":107,"line":167},[105,908,240],{"class":122},[105,910,94],{"class":863},[105,912,913],{"class":213}," user-name",[105,915,869],{"class":122},[105,917,872],{"class":129},[105,919,875],{"class":122},[10,921,923],{"id":922},"related-guides","Related Guides",[62,925,926,933,939],{},[65,927,928],{},[929,930,932],"a",{"href":931},"\u002Fguides\u002Fnaming-conventions-guide","Naming Conventions Guide",[65,934,935],{},[929,936,938],{"href":937},"\u002Fguides\u002Fcamelcase-vs-snake-case","CamelCase vs Snake Case",[65,940,941],{},[929,942,944],{"href":943},"\u002Fguides\u002Fcode-readability-tips","Code Readability Tips",[10,946,948],{"id":947},"try-it-yourself","Try It Yourself",[15,950,951,952,955,956,22,958,955,961,964],{},"Need to convert component names between casings? Transform ",[19,953,954],{},"user-profile"," to ",[19,957,94],{},[19,959,960],{},"snake_case",[19,962,963],{},"PascalCase",", and more with our free tool.",[15,966,967,968],{},"👉 ",[929,969,971],{"href":970},"\u002Ftools\u002Fcase-converter",[57,972,973],{},"Free Case Converter",[975,976,977],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s7hpK, html code.shiki .s7hpK{--shiki-default:#B31D28;--shiki-default-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic}",{"title":101,"searchDepth":115,"depth":115,"links":979},[980,981,985,988,993,999,1000],{"id":12,"depth":115,"text":13},{"id":46,"depth":115,"text":47,"children":982},[983,984],{"id":51,"depth":133,"text":52},{"id":189,"depth":133,"text":190},{"id":297,"depth":115,"text":298,"children":986},[987],{"id":429,"depth":133,"text":430},{"id":476,"depth":115,"text":477,"children":989},[990,991,992],{"id":480,"depth":133,"text":481},{"id":594,"depth":133,"text":595},{"id":685,"depth":133,"text":686},{"id":784,"depth":115,"text":785,"children":994},[995,996,997,998],{"id":788,"depth":133,"text":789},{"id":802,"depth":133,"text":803},{"id":826,"depth":133,"text":827},{"id":840,"depth":133,"text":841},{"id":922,"depth":115,"text":923},{"id":947,"depth":115,"text":948},"2026-05-28","Why Vue and React frameworks mandate PascalCase and how to enforce it in your codebase.","md",{"immutable":136},"\u002Fguides\u002Fpascalcase-component-naming",{"title":5,"description":1002},"guides\u002Fpascalcase-component-naming","OxpJuBMcajTFoSdoYvVy489S5PrK73lXhc592650esA",1780401335588]