Volume I index
Components Before Abstractions

Component Identity and Capitalization

Ishtmeet Singh @ishtms/July 14, 2026/8 min read
#react#components#jsx#identity#capitalization

A lowercase JSX name selects a host element. An uppercase JSX name reads a JavaScript binding.

jsx
<section />
<LessonCard />

React must know whether the next element uses the same component type as the previous element. That decision affects whether React can preserve an existing component instance or must remove it and create another one.

Identity begins with the value placed in the element's type field. Capitalization controls how JSX obtains that value.

Lowercase Names Produce Host Type Strings

JSX transforms a lowercase name into a string type.

jsx
const element = <article />;

Conceptually, the element contains this type.

text
type "article"

React DOM recognizes the string as a browser host element. It can create an HTMLElement with that tag name and apply supported DOM props.

The source does not search for a JavaScript variable named article.

jsx
const article = "unused local value";

function App() {
  return <article />;
}

The local binding has no effect on the JSX type. Lowercase syntax remains the string article.

HTML element names should use their normal lowercase spellings.

jsx
<main>
  <h1>ReactBook</h1>
</main>

React DOM forwards the result to the browser host environment. Browser semantics still apply, including valid nesting, form behavior, and accessibility.

Uppercase Names Read JavaScript Bindings

An uppercase JSX name is compiled as a JavaScript identifier.

jsx
function LessonCard() {
  return <article>Component Identity</article>;
}

const element = <LessonCard />;

Conceptually, the element type refers to the function value.

text
type LessonCard

React sees a function component type and calls it during rendering.

The binding must exist in the current module scope. This fails before React can render the component.

jsx
const element = <LessonPanel />;

If LessonPanel was never declared or imported, JavaScript cannot resolve the identifier. The error belongs to the binding, not to a missing browser tag.

Renaming the Function Changes the Binding

This function begins with lowercase.

jsx
function lessonCard() {
  return <article>Component Identity</article>;
}

Using <lessonCard /> asks React DOM for a host tag string named lessonCard. It does not call the function.

Rename the binding and its JSX use.

jsx
function LessonCard() {
  return <article>Component Identity</article>;
}
jsx
<LessonCard />

The uppercase name now resolves to the function.

React can warn when a lowercase name does not match a recognized HTML element, but a warning is not the design mechanism. The source must use the correct name category.

An Uppercase Alias Works

JSX only needs an uppercase binding whose value is a supported component type.

jsx
function LessonCard() {
  return <article>Component Identity</article>;
}

const Card = LessonCard;

Both elements use the same function value as their type.

jsx
<LessonCard />
<Card />

The displayed component name in development tools normally follows the function's own name or an assigned display name. The local alias controls source lookup, while the underlying function identity remains the same value.

A lowercase alias does not work through JSX component syntax.

jsx
const card = LessonCard;
<card />

That element uses the host type string card. Capitalization is decided by the JSX source name, not by the value stored in the lowercase variable.

Choose a Component Type Through a Variable

An application can select one of two component functions.

jsx
function ReadingView() {
  return <p>Continue reading</p>;
}

function ReviewView() {
  return <p>Review completed lessons</p>;
}

Assign the selected function to an uppercase variable.

jsx
const CurrentView = reviewing ? ReviewView : ReadingView;
return <CurrentView />;

JSX reads CurrentView as a binding. Its current value becomes the element type.

This is different from choosing a ready-made element.

jsx
const currentView = reviewing
  ? <ReviewView />
  : <ReadingView />;

The first pattern stores a component type. The second stores a React element value. Both can be valid, but the variable holds a different category.

text
CurrentView holds a function component type
currentView holds an element description

Name capitalization helps reveal that distinction in source.

Member Expressions Can Name Components

JSX supports a property access whose leftmost binding begins with uppercase.

jsx
const Chapter = {
  Heading: ChapterHeading,
  Progress: LessonProgress,
};
jsx
<Chapter.Heading />
<Chapter.Progress />

JSX evaluates the property and uses its value as the element type.

This syntax can group related exported components, but an object namespace adds another access step. Use it when the grouping has a real public meaning. Separate imports are simpler for the first application.

jsx
import { ChapterHeading, LessonProgress } from "./chapter-ui.jsx";

The Function Object Provides Type Identity

JavaScript functions are objects with reference identity.

jsx
function LessonCard() {
  return <article>One lesson</article>;
}

The LessonCard binding refers to one function object created when the module is evaluated. Every normal render of <LessonCard /> uses that same function reference.

React uses the type along with the element's position and key to decide whether a rendered occurrence corresponds to an existing component instance. At the type level, the same function reference means the same component type.

text
previous type LessonCard
next type LessonCard
  -> type can match

previous type LessonCard
next type ChapterCard
  -> type does not match

When the type changes at a position, React removes the previous component instance and builds the next type's instance. Local state below the previous instance does not transfer automatically.

Nested Definitions Create New Types

This source declares LessonCard each time App runs.

jsx
function App() {
  function LessonCard() {
    return <article>One lesson</article>;
  }

  return <LessonCard />;
}

Every call to App creates a new function object. The source name remains LessonCard, but the reference differs from the previous render.

text
first App render  -> LessonCard function A
second App render -> LessonCard function B

React sees another component type at that position. Once LessonCard has local state, the new type causes that state to reset.

Declare component functions at module level.

jsx
function LessonCard() {
  return <article>One lesson</article>;
}

function App() {
  return <LessonCard />;
}

The module creates the function once. Later App renders keep referring to the same type.

An inline event handler is different.

jsx
<button onClick={() => console.log("open")}>Open</button>

The arrow function is a callback prop, not an element type. Creating a handler function during render does not replace the button's host type.

Type Identity Differs from File Identity

React does not preserve a component because it lives in a particular filename. React receives JavaScript values after modules load.

Move LessonCard to another file while keeping the imported function stable during a normal application build, and its role is still defined by the function used as the element type.

During Fast Refresh, development tooling attempts to associate edited component exports across module updates. Those development-only preservation rules do not replace normal runtime component identity.

The filename helps humans and tools locate source. The function reference is what React receives as type.

Custom Elements Keep Lowercase Tag Syntax

The web platform supports custom elements with hyphenated names.

jsx
<reading-progress value="2"></reading-progress>

This lowercase hyphenated name refers to a browser custom element, not a React function component. React DOM passes supported properties and attributes to that host element according to current React custom-element behavior.

Do not capitalize a custom-element tag unless you created and imported a React wrapper component with that uppercase binding.

jsx
function ReadingProgress(props) {
  return <reading-progress {...props} />;
}

The two types are distinct. ReadingProgress is a React component function. reading-progress is a host custom-element tag.

Use Names that Retain Meaning in a Tree

React DevTools and component stacks display component names.

text
App
  ChapterPage
    LessonList
      LessonCard

Each name identifies the UI responsibility held at that point. A tree containing Wrapper, Container, Item, and Thing provides less source information.

Names should remain specific without encoding the entire parent chain.

text
LessonCard

is clearer than

text
AppMainContentChapterSectionLessonCardComponent

The module path and parent tree already supply surrounding context.

Test Identity with a Controlled Edit

Add a temporary render log to LessonCard.

jsx
function LessonCard() {
  console.log("LessonCard render");
  return <article>One lesson</article>;
}

Render it through <LessonCard /> and confirm the log. Then change the JSX name to lowercase without changing the declaration.

jsx
<lessonCard />

React no longer calls the function through that element, so the log does not come from it. Restore the uppercase name and remove the temporary log.

The test connects capitalization to an observable function call rather than treating it as a formatting convention.

Lesson Check

The following source forms now have distinct meanings.

text
<article /> uses the host type string "article"
<LessonCard /> reads the LessonCard binding
<CurrentView /> reads whichever component type the binding holds
<Chapter.Heading /> reads a property value as the type
<reading-progress /> uses a browser custom-element tag

A stable module-level component function provides a stable type reference. Moving it into another module does not change the identity model; the importer still supplies that function as the element type.

Source Notes