Skip to main content

Code Style

This guide covers naming conventions, Styled Components patterns, and file organization. Following these conventions keeps the codebase consistent and predictable.

Naming conventions

ElementConventionExample
ComponentsPascalCaseUserProfile, NavigationMenu
Component filescamelCaseuserProfile.component.tsx
DirectoriescamelCaseuserProfile/
Props typesPascalCase + PropsUserProfileProps
Styled componentsPascalCase + StyledUserProfileStyled
MapperscamelCase + MapperuserProfileMapper
ConstantsUPPER_SNAKE_CASEMAX_ITEMS, API_URL
HookscamelCase with use prefixuseUserData, useScroll

Import order

Organize imports in this order, with a blank line between each group:

// 1. React
import React, { useState, useEffect } from 'react';

// 2. External libraries
import { useSelector } from 'react-redux';
import { styled } from 'styled-components';

// 3. Internal modules (absolute paths via ~ or - aliases)
import { selectUser } from '~/redux/selectors';
import { Button } from '~/components/button';

// 4. Relative imports
import { cardMapper } from './card.mapper';
import type { CardProps } from './card.component';

Component structure order

Within a component file, follow this order:

// 1. Types
export type ComponentProps = {
title: string;
isActive?: boolean;
};

// 2. Component
const Component = ({ title, isActive }: ComponentProps) => {
// hooks first
const [open, setOpen] = useState(false);

// handlers
const handleClick = () => setOpen(true);

// render
return (
<ComponentStyled $isActive={isActive} onClick={handleClick}>
{title}
</ComponentStyled>
);
};

// 3. Styled components (after main component)
const ComponentStyled = styled.div<{ $isActive?: boolean }>`
// styles
`;

// 4. Export
export default Component;

Styled Components patterns

Basic pattern

import { styled } from 'styled-components';

const CardStyled = styled.div`
padding: ${({ theme }) => theme.spacing.m};
background: white;
`;

Accessing theme tokens

Always access design tokens via the theme — never hardcode values:

// ✅ Use theme tokens
const Title = styled.h1`
color: ${({ theme }) => theme.colors.zengenti};
padding: ${({ theme }) => theme.spacing.s};

@media ${({ theme }) => theme.mq.min.tablet} {
padding: ${({ theme }) => theme.spacing.m};
}
`;

// ❌ Avoid hardcoded values
const Title = styled.h1`
color: #002033;
padding: 24px;
`;

Transient props ($ prefix)

Props intended only for styling — not passed to the DOM — must be prefixed with $. This prevents React from forwarding them to the HTML element:

type StyledProps = {
$isActive: boolean;
$variant: 'primary' | 'secondary';
};

const ButtonStyled = styled.button<StyledProps>`
background: ${({ $isActive, theme }) =>
$isActive ? theme.colors.contensis : 'transparent'};
font-weight: ${({ $variant }) => ($variant === 'primary' ? 700 : 400)};
`;

// Usage — $ props are consumed by styled-components, not forwarded to <button>
<ButtonStyled $isActive={true} $variant="primary">
Click me
</ButtonStyled>

Extending base components

const BaseButton = styled.button`
padding: ${({ theme }) => theme.spacing.xs} ${({ theme }) => theme.spacing.s};
border-radius: 4px;
border: none;
cursor: pointer;
`;

// Extend with additional styles
const PrimaryButton = styled(BaseButton)`
background: ${({ theme }) => theme.colors.contensis};
color: white;
`;

const OutlineButton = styled(BaseButton)`
background: transparent;
border: 2px solid ${({ theme }) => theme.colors.contensis};
`;

Linting and formatting

Run before committing:

# Check for lint errors
npm run lint

# Auto-fix fixable lint errors
npm run lint:fix

Key rules enforced by ESLint and Prettier:

  • No unused variables
  • Single quotes for strings
  • Trailing commas in multiline structures
  • 2-space indentation
  • Maximum line length of 100 characters