Skip to content

React JS Folder Structure

Spinning Idea edited this page Aug 24, 2022 · 20 revisions

React JS Application Folder structure

There are a number of approaches to structuring the folders within a React JS application. Below is one approach that allows clear convention and organization.

Architecture

General Rules

Use kebab-case lower case for all the filenames

Top Level Folders

Below is the main folder structure under the "src" folder. This is the "source" code that is built and packaged into the deployed application

src
├── assets
├── components
├── config
├── contexts
├── hooks
├── layouts
├── models
├── pages
├── routing
├── services (or stores :))
├── styling
├── tests
└── utilities

Routing

One of the starting points in the application is the router which controls the loading of pages and overall application flow from user/client perspective. This folder encapsulates the router and references to pages and rules around route parameters that are passed into pages as key data points that a given page needs.

See: https://github.com/remix-run/react-router

Example

Keep a consistent name between the page and the route:

<Routes>
  <Route path="/" element={<Home />} />
  <Route path="about" element={<About />} />
  <Route path="sign-in" element={<SignIn />} />
</Routes>

Pages

Pages are the primary building blocks and top level components that are referenced in the router and user requests are routed to by the main router. They are components themselves that leverage other components to compose the page and work surface as a whole. Pages are very strictly scoped (and own specific URL path similar to an API controller owning a route segment). Instead of having a single page application this approach breaks apart the application into an "MPA" or Many Page Application.

This approach is powerful because lets you share components in a clear way that is indicated by the folder structure, thus keeping the architecture well organized and the convention if followed allows reasoning about where to put a component and where one should find it.

The home and about may be simple pages with no child components. The sign in page may have more complexity and a sign-form child component that would go in the "main" component folder in a subfolder with the name of the page (sign-in). If the application grows, and the signin-form component will be used in several pages, signin-form can be moved to the "common" folder into a subfolder called "signin-form".

Tests

A page is supposed to be the result of the composition of other components, which have proper tests, so create a specific directory for them under the tests folder in the pages directory (see more below).

Example

pages
├── home.tsx
├── about.tsx
├── signin.tsx

Components

Components folder contains all the components that are used more than one single time in the app including every feature-specific component.

Create subfolders to differentiate between application, page, and common or shared reusable logic. A button may be used widely on many pages of the application, so that goes into "common" directory. The signup-form component is page specific so that goes into a subfolder with that page name.

Suppose you have two different pages that allow signing in but use the signin-form component, this component can be shared via being put into "common" under a subfolder called "signin-form".

Examples

common

├── components
│   ├── common
│   │   └── button
│   │   │   ├── button.tsx
│   │   └── signin
│   │       └── signin-form.tsx
│   └── signup
│       ├── signup-form.tsx
│   └── home
│   │   ├── getstarted.tsx

Some examples of what can be inserted into the common folder:

Notice also that every single component is placed into a proper directory and follow the naming convention.

button
├── button.tsx
└── index.ts

The application can eventually contain many dozens of components so having a consistent structure is important to avoid confusion and for others to easily find and know where to put new work.

Some key points of this folder:

  • All the component-related files are in this folder.
  • All the exportable modules are put into an index.ts to avoid double name in import.
  • All the files are named in kebab-case.

Questions

  • Where is the button component? -> In the button folder.
  • Where are the stories for this button? -> In the button folder.
  • Where are the tests for this button? -> In the tests folder under components/button folder.

Layouts

Layouts are not pages but rather they are components that layout the application page structure to include menuing and header, footer. If need arises for different layouts you can put them all in this folder.

Example

layout
├── main.tsx
└── auth.tsx

One thing you may notice is the name is not main-layout.tsx but just main, that's because following this reason you would have to rename all the components like table-component.tsx which is weird. Name all the components without the obvious suffix given by the parent directory, and if one needs to underline that an import alias "MainLayout" can used to clarify things within the context of the application shell.

import { Main as MainLayout } from "@/layouts/main.tsx";

Contexts

Contexts are not components but rather provide a way to pass data through the component tree without having to pass props down manually at every level.

There are some cases where you need to create custom contexts to extend application capabilities. Separating out these into a dedicated folder helps share these capabilities that are not themselves components.

Examples

contexts
└── authentication.tsx

See More:

Hooks

Hooks are not components

There are some cases where you need to create custom hooks to extend application capabilities. Separating out these into a dedicated folder helps share these capabilities that are not themselves components.

See More:

Examples

hooks
├── use-auth.ts
└── use-click-outside.ts

Utilities

Often the application and pages or components need shared functions for handling currency or dates or processing collections in javascript (eg formatCurrency function that properly formats and adds a dollar sign - put currency formatting in currency.ts and any date formatting in date.ts)

The utilities folder is the place to put these library functions.

Example

utilities
├── currency.ts
├── dates.ts
└── collections.ts

Also, put constants in a single file to encapsulate them into a specific file.

// @/constants/index.ts
export const SUPPORT_EMAILADDRESS = "support@email.com";
export const SUPPORT_USERNAME = "Support";

// And use them
import { SUPPORT_EMAILADDRESS , SUPPORT_USERNAME } from "@/constants";

Models (as needed view models or service models)

The models folder holds any view models that are typed interfaces or contracts for the outbound calls to services and the responses for the services.

In this application there is one service (GeoService) that has a response model called IGeoServiceLocation that encapsulates the data needed by the application for this service. IGeoServiceLocation is the interface to the GeoService.getCurrentIPAddress method and abstracts the details of that service method so that the UI can be decoupled from the actual GeoService response which has additional un-used data points.

This decoupling and typing of the responses for services can be useful.

Additionally, the models folder can hold view models that are combinations of the service models or are completely separate models used only by the views in the application. This approach is influenced by the Model-View-ViewModel (MVVM) approach from .net/WPF but has been used in a number of front end frameworks over the years to provide contracts to the UI that can be shared across screens.

See More: https://www.evozon.com/model-view-viewmodel-in-reactjs/

Services (or Stores...)

The services folder holds the capabilities to make outbound calls to APIs to get and set data and can include authorization and other things like localization. The subject of using stores or services to manage state and external API communication is a complicated one.

See More: https://github.com/spinningideas/resources/wiki/React-JS-State-Management

Styling (CSS, Fonts, Colors)

Put global styles into a "styling" folder. You can put theming here as well. This folder is meant to encapsulate all the things that involve the CSS and styling of the application including font faces and any third-party libraries.

See UI Kits: https://github.com/spinningideas/resources/wiki/React-UI-Toolkits

Example

Application

styles
├── index.css
├── colors.css
└── typography.css

Components

What about CSS for individual components?

button
├── button.tsx
├── button.module.scss
└── index.ts

If you are using emotion, styled-components, or simply the CSS Modules, put them into the specific component folder, so everything will be optimally packaged.

Tests

In order to separate out tests but create an area for them that follows the larger convention of using pages and components folder and placing that structure containing the tests for these under the "tests" folder so they are centrally located and managed.

Example

tests
├── components
│   ├── common
│   │   ├── button.spec.tsx
│   │   ├── signin-form.spec.tsx
│   └── signup
│   │   ├── signup-form.spec.tsx
├── pages
│   ├── about.spec.tsx
│   ├── home.spec.tsx
│   ├── signup.spec.tsx

Asset Files

The "assets" folder provides a dedicated folder to contain the physical assets such as images (.png, .jpg), font files (.woff) or data like json files (geography data in example below).

Example

assets
├── images
│   ├── logo.png
├── fonts
│   ├── noto-sans.woff
│   ├── noto-sans.ttf
├── data
│   ├── countries.json
│   ├── states.json

Config Files

The config folder provides a dedicated folder to contain Application configuration files like Dockerfiles, Fargate Task Definitions, and so on.

See Also

Clone this wiki locally