-
B1. There are no unhandled errors while code executing.
While data loading and working with the app, there are no errors, the app does not break.
-
B2. The code is cross-browser (the last versions of Chrome, Firefox and Safari), works correctly in LTS version of the server environment (NodeJS, Deno) and does not cause errors on different operating systems (Windows, Linux and MacOS).
-
B3. There are no markup errors.
Validators:
Warnings are allowed.
-
B4. The minimum possible number of HTML elements has been used (no extra elements).
There should be no extra wrappers and blocks that are used for decoration and can be replaced with pseudo-elements.
-
B5. Content images in
<img>
have thealt
attribute filled. -
B6. The size is specified in the
<svg>
tag for inline SVG images. -
B7. Vector graphics are used.
If there are svg images in the design, the use of PNG and other formats is prohibited.
-
B8. The layout of the blocks on the page is made by
flex
and/orgrid
. -
B9.
!important
is forbidden.The
important
keyword is only allowed for overrides in libraries. It is forbidden to use for writing your own styles. -
B10. No global tag styles. Only class selectors or a cascade are used to set styles.
Global styles are only available in global style files (
scaffolding.css
,app.css
,reset.css
(🥲), etc).Bad:
/* components/items-list/styles.module.css */ .wrapper div { display: flex; } p { text-align: center; }
Good:
/* components/items-list/styles.module.css */ .wrapper .column { display: flex; } .text { text-align: center; }
Exceptions:
id
and other selectors other thanclass
selector only allowed to be used to override libraries stylesBad
/* components/items-list/styles.module.css – YOUR component */ #list-item { display: grid; }
Good
/* components/accordion/styles.module.css – YOUR overrides to library components */ #accordion { display: grid; } /* styles/scaffolding.css */ /* root – default convention for the root element in React framework */ #root { min-height: 100vh; }
-
B11. Nesting of selectors is no more than two levels.
Bad
/* components/items-list/styles.module.css */ .wrapper .column .text { text-align: center; } .wrapper { display: grid; .column { background-color: red; .text { text-align: center; } } }
Good:
/* components/items-list/styles.module.css */ .column .text { text-align: center; } .text { text-align: center; } .wrapper { display: grid; .column { background-color: red; } .text { text-align: center; } }
-
B12. While interacting with elements (hovering, clicking, etc.), neither the element itself nor the elements around / inside its block change their position.
-
B13. Non-standard fonts are connected locally.
-
B14. Alternate font options specified.
The font order:
- Main font.
- Safe font.
- Font type.
Example:
/* styles/scaffolding.css */ body { font-family: Roboto, Arial, sans-serif; }
-
B15. Names of variables, parameters, properties and methods begin with a lowercase letter and are written in
camelCase
notation. -
B16. English nouns are used as variable and property names.
Abbreviations in words are prohibited. Abbreviated variable names can be used only if the name is common (
err
,xhr
,evt
,src
,i
and etc). -
B17. Variable names do not use the data type.
Bad:
const filtersArray = ['all', 'past', 'feature']; const catObject = { name: 'Pit', age: 7, };
Good:
const filters = ['all', 'past', 'feature']; const cat = { name: 'Pit', age: 7, };
-
B18. Arrays are named plural nouns.
Bad:
const age = [10, 15, 22]; const name = ['John', 'Pit', 'Brew']; const cat = { name: 'Pit', friend: ['Nike', 'Sof', 'Kat'], };
Good:
const ages = [10, 15, 22]; const names = ['John', 'Pit', 'Brew']; const cat = { name: 'Pit', friends: ['Nike', 'Sof', 'Kat'], };
-
B19. Boolean variables start with a prefix that can be answered with "yes".
Bad:
const login = true; const isNotRemoved = Boolean(!payload); if (isNotRemoved) { } const cat = { name: 'Pit', friend: false, };
Good:
const isLogin = true; const isRemoved = Boolean(payload); if (!isRemoved) { } const cat = { name: 'Pit', hasFriends: false, };
-
B20. Function or method begins with a verb.
Exceptions:
Handler functions or callbacks.
Bad:
const action = (names) => { console.log(names); }; const cat = { name: 'Pit', action() { console.log('Meow'); }, }; const randomNumber = () => Math.random();
Good:
const printNames = (names) => { console.log(names); }; const cat = { name: 'Pit', say() { console.log('Meow'); }, }; const getRandomNumber = () => Math.random();
-
B21. Classes are named with English nouns. The class name starts with a capital letter.
Bad:
class wizard {}
Good:
// class class Wizard {}
In cases when there is one or more acronyms in the class name, it should have the first acronym in uppercase whereas all others be handled as a regular word (only the first letter is capitalized)
Bad:
class XmlHttpRequest {}
Good:
class XMLHttpRequest {}
-
B22. Constant names are written in capital letters.
Words are separated by underscores (
UPPER_SNAKE_CASE
), for example:const MAX_HEIGHT = 6996; const IDX_NOT_FOUND = -1;
-
B23. Enums are named by English nouns and begin with an uppercase (capital) letter. Keys are declared in constant format (with uppercase letters).
Bad:
const statusCodes = { ok: 200, notFound: 404, badRequest: 400, };
Good:
const StatusCode = { OK: 200, NOT_FOUND: 404, BAD_REQUEST: 400, };
In cases when there is one or more acronyms in the enum name, it should have the first acronym in uppercase whereas all others be handled as a regular word (only the first letter is capitalized)
Bad:
const HttpStatusCode = {};
Good:
const HTTPStatusCode = {};
-
B24.
kebab-case
is used to name files/folders (names are written in lowercase letters, words are separated by hyphens).In order to avoid name conflicts in different operating systems, it is better to use the least conflicting way of naming files — lowercase letters separated by a hyphen.
Bad
// src/components/common/Button/Button.tsx // src/services/UserService/UserService.ts
Good
// src/components/common/button/button.tsx // src/services/user-service/user-service.ts
Exceptions:
Framework/library files that cannot work with another case.
-
B25. There is no transliteration in any form (in file names, classes, variables, etc.).
-
B26. The code matches the style of the project.
There are no errors while checking the project with linters (ESLint, StyleLint, Prettier, etc). All types of linters are at the discretion of the team.
Rules are not disabled anywhere in the source code.
-
B27. Curly braces are required everywhere.
In any constructions that imply the use of a code block (curly braces), such as
for
,while
,if
,switch
,function
, the code block is necessarily used, even if the statement consists of one line.Bad
if (x % 2 === 1) isEven = false; switch (actionType) { case ActionType.START_LOADING: return { ...state, isLoading: true, }; case ActionType.END_LOADING: return { ...state, isLoading: false, }; }
Good
if (x % 2 === 1) { isEven = false; } switch (actionType) { case ActionType.START_LOADING: { return { ...state, isLoading: true, }; } case ActionType.END_LOADING: { return { ...state, isLoading: false, }; } }
The exceptions are single-line arrow functions, which can be used without the required blocks of code:
const checkedCheckboxes = checkboxes.filter((checkbox) => checkbox.checked);
-
B28. All source files follow the recommended structure.
// 1. Imports import { getUniqueItems } from 'helpers'; // 2. Types / Variables whose value is known before the program starts const COLORS = ['red', 'green', 'blue']; // 3. Variables whose value is known before main code execution const colorPicker = document.querySelector('.color-picker'); // 4. Functions const getUniqueColors = (userColors, defaultColors) => { return getUniqueItems(userColors, defaultColors); }; // 5. Program code const rightColors = getColorsIntersection(colorPicker.value, DEFAULT_COLORS); // 6. Exports export { rightColors };
Some blocks may be missing, but the rest should still adhere to the order.
-
B29. Sets of constants of the same type are collected into Enums.
Bad:
const LOAD_USERS_START = 'LOAD_USERS_START'; const LOAD_USERS_END = 'LOAD_USERS_END'; const LOAD_USERS_ERROR = 'LOAD_USERS_ERROR';
Good:
const UserAction = { LOAD_START: 'LOAD_START', LOAD_END: 'LOAD_END', LOAD_ERROR: 'LOAD_ERROR', };
Note: constants that are used in the same context, but has different purposes should be split into different enums or separate constants
Bad:
const CompensationComputation = { HOLIDAY_COMPENSATION: 1.7, OVERTIME_COMPENSATION: 1.5, OVERTIME_THRESHOLD: 1.1, //related not to compensation rate, but to overtime hours calculation };
Good:
const CompensationCoefficient = { HOLIDAY_COMPENSATION: 1.7, OVERTIME_COMPENSATION: 1.5, }; const OVERTIME_THRESHOLD = 1.1;
-
B30. All class properties and methods are marked with member access (private , public or protected).
Bad:
class Animal { constructor({ name }) { this.privateName = name; } getPrivateName() { return this.privateName; } }
Good:
class Animal { #privateName; public constructor({ name }) { this.#privateName = name; } public getPrivateName() { return this.#privateName; } } // or class Animal { private privateName; public constructor({ name }) { this.privateName = name; } public getPrivateName() { return this.privateName; } }
-
B31. The code does not use “magic values”, each of them has a separate variable named as a constant.
-
B32. The versions of dependencies used are fixed in
package.json
.The dependency lists in the package.json file indicate the exact versions of the packages used. The version must be specified.
^
,*
and~
are not allowed. -
B33. There are no unused dependencies in the project.
Node: Some dependencies are needed by other dependencies. Ex.
pg
package is required for most of ORM packages. -
B34. There are no files, modules and parts of code that are not used in the project code, including commented code pats.
There are no script files that are “dead code” that is never executed.
-
B35. Constants and enums are not redefined anywhere in the code.
-
B36. Potentially incorrect operations are missing. API is used correctly.
For example, sum of two values with different data types.
Bad:
new Date() + 1000;
Good:
Number(new Date()) + 1000;
Potentially incorrect operation of taking the integer part of a number.
Bad:
const minutesNumber = ~~(seconds / 60);
Good:
const minutesNumber = Math.trunc(seconds / 60);
Valid values are passed as expected by the specification.
Bad:
const isPressed = element.getAttribute('aria-pressed', false);
Good:
const isPressed = element.getAttribute('aria-pressed');
map
method returns a value, so either this value should be used, or the method should be replaced withforEach
.Bad:
let greeting = 'Hey'; wizards.map((wizard) => { greeting += `, ${wizard.name}`; }); console.log(`${greeting}!`);
Good:
const greeting = 'Hey'; const names = wizards.map((wizard) => { return wizard.name; }); console.log(`${greeting} ${names.join(', ')}!`);
-
B37. Modules do not export mutable variables.
A module should not export a variable whose value may change in the future.
Bad:
let latestResult; export { latestResult };
Good:
const latestResult = loadLatestResult(); export { latestResult };
-
B38. The name of the module corresponds to its content.
Different logical parts of the code are placed in separate module files. The name of the module must match its content. For example, if the module contains the
GameView
class, then the name of the module should begame-view.js
. -
B39. No
index
files.index
file can be only used as the entry point of the application.
-
B40. Event handlers are added and removed in a timely manner.
Event handlers are added only when the element appears on the page and are removed when it disappear.
-
B41. 🗄 It is forbidden to use the GET method to write data.
-
B42. 🗄 There are no SQL Injections in the code.
While working with a database, all SQL queries must be protected from SQL injection.
-
B43. 🗄 Code protected from XSS.
It is not allowed to display unfiltered information received from the user, because XSS attack is possible.
-
B44. 🗄 Passwords are always hashed.
-
B45. 🗄 Migrations roll in two ways (up and down) without any errors. Data consistency is preserved after every migration.
-
A1. Modern syntax is preferred.
Prefer modern JS syntax if possible, based on your target of your bundler, usage of transpilers (ex. Babel) and the browsers/platforms you support. See some examples below
Array methods:
Bad:
items.slice().reverse();
Good:
items.toReversed();
Optional Chaining:
Bad:
const userName = user && user.name;
Good:
const userName = user?.name;
Nullish coalescing:
Bad:
const userCreatePayload = payload || INITIAL_USER_CREATE_PAYLOAD_VALUES;
Good:
const userCreatePayload = payload ?? INITIAL_USER_CREATE_PAYLOAD_VALUES;
Top-level await:
Bad:
(async () => { await app.run(); })();
Good:
await app.run();
-
A2. All interactive elements have a description.
Bad:
<input placeholder="First Name" /> <button onClick={handleEditUserClick}></button> <a href={AppRoute.DASHBOARD}></a> <button onClick={handleEditUserClick}><img src="img/user.svg" /></button> <a href={AppRoute.DASHBOARD}><img src="img/arrow.svg" /></a>
Good:
<label class="visually-hidden" for="first-name">First name</label> <input id="first-name" placeholder="First Name" /> <button onClick={handleEditUserClick}> <span className="visually-hidden">Edit user</span> </button> <a href={AppRoute.DASHBOARD}> <span className="visually-hidden">Go to dashboard</span> </a> <label> <span class="visually-hidden">First name</span> <input placeholder="First Name" /> </label> <button onClick={handleEditUserClick}> <img src="img/user.svg" alt="" /> <span className="visually-hidden">Edit user</span> </button> <a href={AppRoute.DASHBOARD}> <img src="img/arrow.svg" alt="" /> <span className="visually-hidden">Go to dashboard</span> </a> <input aria-label="First name" placeholder="First Name" />
-
A3. Uniform writing and formatting of code in all file types (HTML, CSS, JS, JSX, ect.).
Example:
If you use css-nesting it should be used through all the project (all style files must be written using nesting). If you use interfaces with
I
(ex.IUser
) approach it should be used through all the project (all interfaces must be written withI
prefix). If you use TS Enums approach it should be used through all the project (you can not use both TS Enum and JS Enum (JS plain object withas const
)). -
A4. Abstract classes or interfaces should have generic names and do not contain implementation details.
-
A5. The names of methods/functions and properties/variables of objects do not contain the names of object/module.
Bad:
const popup = { openPopup() { console.log('I will open popup'); }, }; const wizard = { wizardName: 'Gandalf', };
Good:
const popup = { open() { console.log('I will open popup'); }, }; const wizard = { name: 'Gandalf', };
Bad:
// src/validation-schemas/users/login.validation-schema.ts const userValidationSchema = {};
Good:
// src/validation-schemas/users/login.validation-schema.ts const user = {}; // src/components/sign-in/sign-in.tsx import { user as userValidationSchema } from 'validation-schemas';
-
A6. 🔵 Interfaces are only used to
implement
a class. -
A7. A uniform naming style for variables is used.
Variable naming style is used the same in all modules, for example:
If the variables that store the DOM element contain the word Element or anything else, it must be the same everywhere
Bad:
const popupMainElement = document.querySelector('.popup'); const sidebarNode = document.querySelector('.sidebar'); const similarContainer = popupMainElement.querySelector('ul.similar');
Good:
const popupMainElement = document.querySelector('.popup'); const sidebarElement = document.querySelector('.sidebar'); const similarContainerElement = popupMainElement.querySelector('ul.similar');
Also good
const popupMainNode = document.querySelector('.popup'); const sidebarNode = document.querySelector('.sidebar'); const similarContainerNode = popupMainNode.querySelector('ul.similar');
-
A8. One approach is used while using API that supports multiple approaches.
If there are several different APIs that allow you to solve the same problem, for example, finding an element by id in the DOM tree, then only one of these APIs is used in the project.
Bad:
const popupMainElement = document.querySelector('#popup'); const sidebarElement = document.getElementById('sidebar'); const popupClassName = popupMainElement.getAttribute('class'); const sidebarClassName = sidebarElement.className;
Good:
const popupMainElement = document.querySelector('#popup'); const sidebarElement = document.querySelector('#sidebar'); const popupClassName = popupMainElement.getAttribute('class'); const sidebarClassName = sidebarElement.getAttribute('class'); // or const popupMainElement = document.getElementById('popup'); const sidebarElement = document.getElementById('sidebar'); const popupClassName = popupMainElement.className; const sidebarClassName = sidebarElement.className;
-
A9. ⚛️ Callbacks passed to
props
are named withon
prefix.<ListItem onClick={handleBtnClick} />
-
A10. ⚛️ Component functions are named with
handle
prefix.const Dashboard = () => { const handleBtnClick = () => {}; return <ListItem onClick={handleBtnClick} />; };
- A11. If the same code is repeated in several modules, the repeated part is moved to a separate module.
-
A12. Where possible, the ternary operator is used in the assignment of a value instead of if.
Exceptions:
Ternary operator should not be nested.
Bad:
let sex; if (isMale) { sex = 'Man'; } else { sex = 'Woman'; }
Good:
const sex = isMale ? 'Man' : 'Woman';
-
A13. Conditions are simplified.
If the function returns a boolean value, do not use
if..else
with unnecessaryreturn
.Bad:
const checkIsEquals = (firstValue, secondValue) => { if (firstValue === secondValue) { return true; } else { return false; } };
Good:
const checkIsEquals = (firstValue, secondValue) => { return firstValue === secondValue; };
-
A14. 🔵
unknown
is preferred overany
.any
is prohibited. -
A15. Use the
for/of
to iterate over arrays and data structures that can be iterated over(Iterable).Where an array element index is not required, or where all elements of an iterable data structure need to be traversed, a
for .. of
loop is used instead of afor
loop.Bad:
for (let i = 0; i < levels.length; i++) { const level = levels[i]; renderLevel(level); }
Good:
for (const level of levels) { renderLevel(level); }
-
A16. Long functions and methods are split into several smaller ones.
-
A17. Iterators for arrays are used to work with JS collections.
Iterators are used to with arrays —
forEach
,map
,filter
, and etc.elements.forEach((element) => { element.addEventListener('click', () => { console.log(element); }); });