Ultimate ternary folder structure for large React applications

Babek Naghiyev
4 min readApr 15, 2021

--

The hierarchy is mostly this way. But it can change according to the needs.

In some parts of your career, you will come across large React applications. Let’s keep it petite and clear.

The main code for the “Ternary design system” is “if necessary and possible, classify into 3 parts”. Everything at some point may become 1 of 3.

Let’s go deeper by starting from the src/ folder:

common/
components/
pages/

This pattern unpredictably makes sense. We can cover our whole app source tree with this triple structure.

common/ folder has all functionality of common usage obviously:

common/
config/
routes/
constants/
styles/
theme.js
services/
store/
utils/
types/
assets/
locales/
hooks/

Folders inside the common/ folder are out of the ternary design in this example, as it fails to comply with all the rules. It can’t and needn’t be classified. Grouping them may be a great annoyance.

pages/ folder should also rely on this very strategy. Let's assume we have a pages/Home/ page and create a better architecture for it:

__tests__/
ui/
common/

pages/Home/ui/ relies on the core concept of this article the most.

  • Partials are layout building blocks of pages. Example: Header, Content, Footer, Sidebar. A sidebar can be both partial if it possesses page scope or block if it doesn’t.
  • Blocks are compositions of 2 or more components logically or positionally. They form partials together. Example: EditForm, Filter, Sorter, AccountDetails, Wizard, etc. If it seems challenging to find semantic names for them, you can use their position: TopLeft, Top, Middle, etc.
  • Components are familiar to everyone. These smallest parts of our whole tree are more maintainable and globally useful. Sometimes even a page can become a “component” by its reusability. So the trademark of components is “reusable”.

See how easy it is to find a component:

partials/ # groups blocks
Header/
index.js
Header.js
Loadable.js # Lazy loads
Header.module.sass
Body.js
Footer.js
blocks/ # groups components
CashRegister/
ClientComplaints/
components/
ExceptionallyGreatModal/
__tests__/
common/
components/
ExceptionallyGreatModalHeader.js
ExceptionallyGreatModalBody.js
ExceptionallyGreatModalFooterjs
ExceptionallyGreatModal.js
ExceptionallyGreatModal.module.sass
index.js # exports ExceptionallyGreatModal.js
Loadable.js # Lazy loads ExceptionallyGreatModal.js

Everything directly under theExceptionallyGreatModal/ folder can only do primary and direct tasks of ExceptionallyGreatModal.js . If you are planning to create a component as ExampleComponent.js or data.js , should create an inclusive folder like components/ or common/ .

Let’s visualize partials, blocks, and components for better understanding:

Blocks can also be named by their position like TopLeft, MiddleRight, etc.

This structure will make your React app maintainable and readable. Any other developer will easily carry on where the predecessor stopped. It can also be used to simplify large components.

The final picture is:

pages/

Home
__tests__/
index.js # exports Home.js or routing
Loadable.js # exports Home.js lazily
Home.js # calls layouts
Home.module.sass
ui/
partials/ # groups blocks
Header.js
Body.js
Footer.js
blocks/ # groups components
CashRegister/
VatAccountBlock/
components/
__tests__/
ExceptionallyGreatModal/
index.js
Loadable.js
ExceptionallyGreatModal.js

common/
routes/
functions/
tools/
redux/
lang/

Envision a larger project page with many pages included. On every step, you divide large code into 3:

pages/
LargePage/
__tests__/
common/

ui/
partials/
blocks/
components/

pages/
SmallPage1/
partials/
blocks/
components/
SmallPage2/

Apparently, since it is unnecessary, we broke the ternary design method inside the pages/ui/ folder by adding 4 folders in it. Different projects may require different techniques and no structure is written on the stone. The main point here is to make our code more readable and fitting to SOLID principles, thus we did. Here how the ExamplePage.js page looks like:

# Page
export const ExamplePage = () => (
<Layout>
<Header />
<Content />
<Footer />
</Layout>
);

The Content.js partial is as follows:

# Partial
export const Content = () => (
<ContentLayout>
<Top />
<Sidebar />
<SampleBlock />
</ContentLayout>
);

Blocks are named according to the partnership of the included components. If you can’t find relevant names, use their positions: TopLeft, MiddleRight, etc.

SampleBlock.js block:

# Block
export const SampleBlock = () => (
<SampleBlockLayout>
<TabComponent />
<SampleMap />
</SampleBlockLayout>
);

If you have any comments, please let me know. I wish you like it.

Share to make the world a better place :)

--

--

Babek Naghiyev
Babek Naghiyev

Written by Babek Naghiyev

Senior Software Engineer (Frontend)

No responses yet