Skip to main content
Trezor Suite follows strict coding conventions to maintain consistency across the codebase. All code must adhere to these guidelines before merging.

Formatting Tools

Trezor Suite uses automated formatting tools to enforce code style:

Prettier

Handles code formatting automatically

ESLint

Enforces code quality and catches errors

Prettier Configuration

The project uses the following Prettier settings:
.prettierrc
{
  "printWidth": 100,
  "arrowParens": "avoid",
  "bracketSpacing": true,
  "singleQuote": true,
  "semi": true,
  "tabWidth": 4,
  "useTabs": false,
  "bracketSameLine": false
}
YAML files use 2-space indentation instead of 4 spaces.

Running Formatters

Always format your code before committing changes.
yarn g:prettier --write <changed-files>
yarn g:eslint --fix <changed-files>

Basic Syntax Rules

If-Else Statements

Always use braces for if-else blocks, except for simple inline-if without else:
if (condition) doSomething();

Code Spacing

Use empty lines to structure code into logical groups:
export const getPrerequisites = ({ router, device, transport }: PrerequisitesInput) => {
    const excluded = getExcludedPrerequisites(router);
    const prerequisite = getPrerequisiteName({ router, device, transport });
    if (typeof prerequisite === 'undefined') return;
    if (excluded.includes(prerequisite)) return;
    return prerequisite;
};
Group related declarations together, separated from conditional logic by empty lines.

Function Parameters

For functions with more than two parameters, wrap them in an object:
const logAnimalNames = (cat: string, dog: string, guineaPig?: string, showHeading?: boolean) => {
    if (showHeading) {
        console.log('My Animals');
    }
    console.log(cat);
    console.log(dog);
    if (guineaPig) {
        console.log(guineaPig);
    }
};

// Confusing call - what does true mean?
logAnimalNames('Nancy', 'Rob', null, true);

Conditional Rendering in React

Always ensure JSX conditions evaluate to boolean values only.
React can render values like 0, "", or [], which may cause unexpected behavior:
// Could render 0 if value is 0
{value && <Component value={value} />}

Import and Export

Named Exports Only

Use named exports exclusively for consistency and better tree-shaking.
Good
export const myFunction = () => {};
export const MyComponent = () => {};
Bad
const MyComponent = () => {};
export default MyComponent;
Benefits:
  • Easier refactoring with mass-replace
  • Better tree-shaking support
  • Consistent naming across imports
  • Easier code searching
Storybook files are exempt from this rule as they require default exports.

Barrel Files

  • Use index.ts files only in packages to define public interfaces
  • Do not use them inside modules to export from directories
  • They can introduce circular dependencies and hurt tree-shaking

Naming Conventions

General Rules

1

Values = Nouns

Variables and constants should be nouns:
const userAccount = ...;
const networkSymbol = 'btc';
2

Functions = Verbs

Functions should start with action verbs:
const getUserData = () => ...;
const calculateTotal = () => ...;
3

Booleans = Questions

Boolean values should ask a question:
const isDisabled = true;
const hasFinished = false;
const canProceed = checkPermissions();
4

Components = Nouns

React components should always be nouns:
const AccountSelector = () => ...;
const TransactionList = () => ...;

Abbreviations

Use all capital letters for abbreviations:
Good
const someFAQConstant = ...;
function enterTHPPairingCode() {}
Bad
const someFaqConstant = ...;
function enterThpPairingCode() {}

Component Props Interface

Always name component interfaces with the Props suffix:
interface ButtonProps {
    label: string;
    onClick: () => void;
}

const Button = ({ label, onClick }: ButtonProps) => {
    return <button onClick={onClick}>{label}</button>;
};

Suite-Specific Naming

Crypto Networks

// Good
const network = networks['btc'];

Fiat Currencies

Always prefix fiat-related names with fiat:
Good
const fiatCurrency = 'usd';
const selectFiatCurrency = () => 'usd';
const formatFiatCurrency = value => value;
Bad
const currency = 'usd';
const selectCurrency = () => 'usd';
const formatCurrency = value => value;

Assets

Asset refers to a group of accounts for the same network:
Good - List of asset groups
const AssetsList = () => <... />;
Good - Single account detail
const AccountDetailScreen = () => <Screen />;
Bad - Confusing terminology
const AssetDetailScreen = () => <Screen />; // Asset is multiple accounts, not one

Comments

All comments must start with an uppercase letter and end with a period:
// This is a comment that will help you understand what is happening in the
// code below.
const someFunction = () => null;

ESLint Rules

Key ESLint rules enforced in the project:
'import/no-extraneous-dependencies': 'error'
'no-restricted-imports': [
  'error',
  {
    patterns: [
      {
        regex: '/libDev/src',
        message: 'Importing from "*/libDev/src" path is not allowed.',
      },
    ],
  },
]
Storybook files (*.stories.tsx) have relaxed rules:
  • Default exports are allowed
  • Hooks can be used outside components

Component Structure

Follow this order when organizing component files:
1

1. Imports

Import statements at the top
2

2. Styles

Styled components or style definitions
3

3. Constants

Component-level constants
4

4. Helpers

Component-level helper functions
5

5. Types

Type definitions and interfaces
6

6. Props Type

Component props interface
7

7. Component

The component implementation

Inside Components

Maintain consistent ordering within component bodies:
  1. Redux selectors (global state)
  2. useState (local state)
  3. Non-effect hooks (useRef, useForm, useDispatch)
  4. Effects (useEffect)
  5. Functions and callbacks
  6. Derived values and sub-components
  7. Render/return statement

Passing Props to Components

Pass only the necessary properties, not entire objects.
const DeviceVersion = ({ version }) => <div>{version}</div>;

<DeviceVersion version={device.version} />
Benefits:
  • Clearer component interface
  • Prevents unnecessary re-renders
  • Easier to identify dependencies

Prop Drilling and Identifiers

Use Redux selectors as the primary source for complete data.
For data with identifiers (like accounts, devices):
  • Pass only the identifier (ID/key) as props
  • Each component fetches complete data using selectors
  • This prevents unnecessary re-renders and prop drilling
Good - Passing identifiers
const ParentComponent = ({ accountKey }) => {
    const account = useSelector(state => selectAccountById(state, accountKey));
    
    return <ChildComponent accountKey={accountKey} />;
};

const ChildComponent = ({ accountKey }) => {
    const account = useSelector(state => selectAccountById(state, accountKey));
    
    return <div>{account.balance}</div>;
};

Resources

Prettier Config

Official Prettier documentation

ESLint Rules

ESLint rule reference

TypeScript Guide

TypeScript-specific conventions

Component Guidelines

React component best practices

Build docs developers (and LLMs) love