PascalCase for Component Naming
Why PascalCase for Components
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 (<div>, <span>, <button>). PascalCase names (<UserProfile>, <SearchBar>) immediately distinguish custom components from native elements.
Without this convention, <userprofile> 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.
Framework Rules
Vue
Vue's style guide lists PascalCase component names as essential (the strongest category). The rules:
- Component files:
UserProfile.vue,SearchBar.vue - In templates:
<UserProfile />or<user-profile />(both work, but PascalCase is preferred) - In
componentsregistration:UserProfile
// Component registration
import UserProfile from './UserProfile.vue'
export default {
components: {
UserProfile // PascalCase key
}
}
Vue auto-imports in Nuxt follow the same rule: components/UserProfile.vue becomes <UserProfile>.
React
React requires PascalCase more strictly — lowercase component names render as native HTML elements:
// This renders a <userprofile> HTML element — NOT your component
function userprofile() { return <div>Hello</div> }
<userprofile /> // BUG: renders unknown HTML element
// This renders your React component correctly
function UserProfile() { return <div>Hello</div> }
<UserProfile /> // Correct
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.
Naming Patterns by Component Type
| Component Type | PascalCase Example | File Name |
|---|---|---|
| Page section | HeroSection | HeroSection.vue |
| UI primitive | BaseButton | BaseButton.vue |
| Layout | AppHeader | AppHeader.vue |
| Form | LoginForm | LoginForm.vue |
| List item | ProductCard | ProductCard.vue |
| Modal/dialog | ConfirmDialog | ConfirmDialog.vue |
| Utility | AnimatedCounter | AnimatedCounter.vue |
Prefix Conventions
Many teams add prefixes to signal component categories:
- Base:
BaseButton,BaseInput— reusable primitives - App:
AppHeader,AppSidebar— application layout components - The:
TheNavigation,TheFooter— singleton components (one per page)
These prefixes are optional but help organize large component libraries.
Enforcing PascalCase
ESLint for Vue
// eslint.config.js
import vuePlugin from 'eslint-plugin-vue'
export default [
...vuePlugin.configs['flat/recommended'],
{
rules: {
'vue/component-definition-name-casing': ['error', 'PascalCase'],
'vue/component-name-in-template-casing': ['error', 'PascalCase'],
}
}
]
ESLint for React
// eslint.config.js
import reactPlugin from 'eslint-plugin-react'
export default [
{
rules: {
'react/jsx-pascal-case': ['error', {
allowAllCaps: false,
ignore: [],
}]
}
}
]
Nuxt Auto-Import Naming
Nuxt generates component names from file paths. components/tools/JsonFormatter.vue becomes ToolsJsonFormatter. To keep names clean:
- Use flat directories for frequent components:
components/SearchBar.vue→<SearchBar> - Use nested directories for grouping:
components/admin/UserTable.vue→<AdminUserTable> - Configure path prefixes in
nuxt.config.tsif needed
// nuxt.config.ts
export default defineNuxtConfig({
components: [
{ path: '~/components', pathPrefix: false }, // Flat naming regardless of directory
]
})
Common Mistakes
1. Abbreviated Names
Avoid UsrPrfl or BtnGrp. Component names should be descriptive. The extra characters cost nothing in terms of performance, but cryptic names cost a lot in readability.
2. Single-Word Names
Button.vue, Form.vue, Table.vue — these collide with native HTML elements and third-party libraries. Prefix them: BaseButton, ContactForm, DataTable.
3. Inconsistent Casing in Templates
Mixing <UserProfile> and <user-profile> in the same project confuses readers. Pick one and enforce it with ESLint.
4. Prop Names in PascalCase
Props should use camelCase in JavaScript and kebab-case in templates — never PascalCase:
<!-- Bad -->
<UserProfile UserName="john" />
<!-- Good -->
<UserProfile userName="john" />
<!-- or in templates: -->
<UserProfile user-name="john" />
Related Guides
Try It Yourself
Need to convert component names between casings? Transform user-profile to UserProfile, snake_case to PascalCase, and more with our free tool.