React components have one inviolable convention — PascalCase for the component name itself — and several team-by-team conventions for file naming, folder structure, and prop naming. Here's a tour of what works.
PascalCase for component names
React requires PascalCase for component names. This isn't a style preference — it's a parsing rule. JSX treats lowercase tag names as HTML elements:
// HTML element (lowercase = built-in)
<div />
// React component (PascalCase = component reference)
<UserProfile />
If you write <userProfile />, React thinks you mean an HTML element called userProfile, which doesn't exist. This is the most common newcomer mistake.
The PascalCase rule applies to:
- Component function/class names:
function UserProfile() { ... } - The JSX tag references:
<UserProfile /> - Named exports of components:
export const UserProfile = () => ...
It does not apply to:
- Props:
<UserProfile userName="..." />— props are camelCase - State variables:
const [userName, setUserName] = useState('')— camelCase - Event handlers:
const handleClick = () => ...— camelCase - Custom hooks:
function useUserData() { ... }— start withuse, then camelCase
File naming: three common patterns
React has no enforced file-naming convention. Three patterns are widely used:
1. PascalCase matching the component
components/
UserProfile.jsx
UserAvatar.jsx
UserSettings.jsx
This is the most common pattern. The file name matches the component name exactly. Imports look like:
import UserProfile from './components/UserProfile';
Strengths: visual symmetry between file and component name. Easy to navigate the file tree because file names match the React tree.
Weaknesses: some build systems and operating systems have case-sensitivity quirks (Windows, macOS default filesystems are case-insensitive; Linux is case-sensitive). A typo like ./UserProfile vs ./userprofile might work locally on macOS and fail in CI on Linux.
2. kebab-case file names
components/
user-profile.jsx
user-avatar.jsx
user-settings.jsx
Some teams (especially Vue migrants) use kebab-case for file names while keeping PascalCase for component names:
// In user-profile.jsx
export default function UserProfile() { ... }
// Imported
import UserProfile from './components/user-profile';
Strengths: kebab-case file names avoid case-sensitivity issues. Matches the URL convention.
Weaknesses: visual mismatch between file and component name. The convention is less common in React-specific tooling.
3. Folder per component with index.jsx
components/
UserProfile/
index.jsx
UserProfile.module.css
UserProfile.test.jsx
types.ts
UserAvatar/
index.jsx
...
Each component gets its own folder with related files (styles, tests, types) co-located. Imports use the folder name:
import UserProfile from './components/UserProfile';
Strengths: keeps related files together. Scales well to components with many associated files. Makes it easy to "delete this whole component" by removing the folder.
Weaknesses: more deeply nested directory structure. Many files named index.jsx can be confusing in editor tabs.
Component naming patterns
Beyond PascalCase, several patterns make component names easier to read and group:
Noun-based names for visual components
Components that render visible UI are conventionally nouns: Button, Card, Modal, UserProfile, NavigationBar. They describe what the component is.
Verb-prefixed names for logical/wrapper components
Components that wrap or modify other components without rendering visible UI sometimes use verbs: WithTheme, WithAuth, WrapInBoundary. These are higher-order components or context providers.
Hook-style names for behavior components
Render-prop components or behavior providers sometimes use a noun-first pattern: FocusTrap, ClickOutside, ScrollSpy. They describe a behavior they provide.
Domain prefixes for namespacing
Large codebases often prefix components by feature area: UserProfile, UserAvatar, UserSettings, OrderList, OrderDetail, OrderForm. This makes file trees and import statements easier to scan.
Container vs. presentational components
An older React pattern (less common now with hooks but still useful) split components into two types:
- Container components: handle data fetching, state, and logic. Often named with a suffix:
UserProfileContainer. - Presentational components: receive data via props and only render UI. Named without suffix:
UserProfile.
With hooks, this split has become less pronounced — most modern components do both. But the naming pattern persists in some codebases.
Custom hook naming
Custom hooks have a strict naming convention: they must start with use followed by a camelCase descriptor. useFormState, useDebounce, useUserData, useLocalStorage.
The use prefix is detected by the React Hooks ESLint plugin and used to enforce the rules of hooks. Hooks named without the use prefix don't get the lint coverage and can lead to subtle bugs.
The descriptor should be a noun phrase (useFormState) or a verb phrase (useDebounce) describing what the hook does. Avoid generic names like useUtility.
Prop naming
Props are camelCase. Convention is to use descriptive names that read like English:
isLoadingfor booleans (alsohasError,canEdit)onClick,onSubmitfor event handlers (lowercaseon+ PascalCase event)userName,userIdfor data (camelCase, descriptive)childrenfor content (React's built-in name; don't rename)renderHeader,renderFooterfor render props
The most important convention: event handler props are on + the event. onClick for click handlers. onSubmit for form submits. onChange for input changes. This matches React's built-in event prop names.
Boolean props
Boolean props should be true/false statements, not flags. Three patterns work:
isDisabled(state)hasIcon(existence)canEdit(permission)
Avoid:
disabled={true}versusdisabled={false}reads OK but ambiguous as justdisabled. Some teams useisDisabledfor clarity.noBorder— negated booleans get confusing. PreferhasBorder={false}.type="primary"for boolean-ish values when it should just be a string enum.
Avoiding name collisions
React doesn't enforce uniqueness of component names within a project — multiple files can export components called Button. This is fine for small projects but causes confusion at scale.
Common patterns to avoid collisions:
- Prefix by feature area:
OrderButton,NavButton,DialogButtonrather than three differentButtoncomponents. - Compound naming for variants:
PrimaryButton,SecondaryButton,IconButton. - Namespace by import path: a generic
Buttonis fine if imports clearly distinguish them (import { Button } from '@/components/forms';).
Index files and barrel exports
A common pattern is to expose components through a barrel index.js file:
// components/index.js
export { UserProfile } from './UserProfile';
export { UserAvatar } from './UserAvatar';
export { UserSettings } from './UserSettings';
// Usage
import { UserProfile, UserAvatar } from '@/components';
This makes imports tidier but creates a few downsides: harder for build tools to tree-shake (some bundlers can't optimize barrel exports as well), longer import chains, slower IDE autocomplete. Use barrels sparingly — they pay off in small APIs (public component libraries) and cost in large codebases.
Folder structure patterns
Three common patterns for organizing React components in a project:
By type
src/
components/
Button.jsx
Card.jsx
Modal.jsx
pages/
Home.jsx
UserProfile.jsx
hooks/
useAuth.js
useUserData.js
Simple and obvious. Works for small projects. Breaks down at scale because every feature touches every folder.
By feature
src/
features/
users/
components/
hooks/
api.js
orders/
components/
hooks/
api.js
shared/
components/
hooks/
Each feature owns its own components, hooks, and logic. Scales well. The downside is that "shared" easily becomes a dumping ground.
By route
src/
app/
page.jsx
users/
page.jsx
[id]/
page.jsx
orders/
page.jsx
The Next.js app-router pattern. Components live where they're rendered. Easy to reason about routing.
Bulk renaming
If you're refactoring a codebase from one convention to another — say, renaming all components from kebab-case file names to PascalCase, or shifting from userProfile camelCase imports to UserProfile — our bulk converter handles a list of identifiers in one pass. Combine the output with a sed script or codemod to update all references.
For converting a single component name between camelCase and PascalCase, the PascalCase converter is fastest.
The bigger principle
React conventions vary between teams more than most languages. The convention itself matters less than:
- That your team has a documented convention
- That the convention is enforced by linters where possible
- That new code follows the convention consistently
- That old code is gradually refactored when touched
The cost of mixed conventions shows up in code review, onboarding, and the slow tax of every developer mentally translating between styles. Pick a convention, document it, and stick to it.