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