- Global Standards
- PHP Coding Standards
- HTML Coding Standards
- SCSS Coding Standards
- JavaScript Coding Standards
Note: When working with existing code try to extrapolate and use standards, naming conventions, formatting of the existing code for uniformity and readability. All new code created should follow the standards outlined below.
Global Standards
- DRY – do not repeat yourself
- KISS – keep it short and simple
- Readable – code must be written for humans first and easily readable and skimmable
PHP Coding Standards
- When working with Drupal, use Drupal’s coding standards as set by the Drupal community.
- When working with WordPress, use WordPress coding standards (use editorconfig to set settings per project).
- When working on a standalone project, use PEAR coding standards.
HTML Coding Standards
HTML Naming Conventions
For all HTML use the web components/ BEM model. This naming convention allows for writing very simple and linear SCSS, improving site performance and code management efficiency.
HTML Code Formatting
- Use 2 spaces for indentation
- Unix-style line endings
- Indent the code based on hierarchy for readability
- For big code chunks, include a trailing comment with the class name to demonstrate which code block is terminated
SCSS Coding Standards
SCSS Naming Convention
Our standards are based on the BEM code writing and organization model. Please see the video presentation to learn what BEM is and why we use it.
- Whenever possible, use design components.
An illustrated guide should help you get started. - See BEM HTML/CSS Class Naming Reference for clear examples & BEM Authoring tool to quickly create code that adheres to these standards.
- Always use a starterkit for a new project, it’s likely to have a scaffold that has many of these standards implemented and ready to go.
SCSS Spacing
- Intent code using 2 spaces for each level of indentation
- Use one selector per line when a ruleset has a group of selectors separated by commas.
- The opening brace (
{
) of a ruleset’s declaration block should be on the same line as the selector (or the same line as the last selector in a group of selectors.) The opening brace should include a single space before it. - Place the closing brace (
}
) of a ruleset in the same column as the first character in the selector of the ruleset.
button,
.button {
}
- Include one declaration per line in a declaration block.
button,
.button {
background-color: palette('button', 'background');
color: palette('button', 'text');
}
- Each declaration should be indented one level relative to its selector.
- Each declaration block should be separated by one blank line. This applies to the nested ones as well. The spacing enables faster and easier reading and comprehension of the code.
figure {
margin: 0 0 px-to-rem($base-line-height / 2);
max-width: 100%;
&.figure--right {
margin: 0 0 px-to-rem($base-line-height / 2) px-to-rem($base-line-height / 2);
}
}
figcaption {
font-family: $caption-font-family;
}
- There MUST NOT be any whitespace (spaces or tabs) at the end of lines.
SCSS Comments
- Provide comments for easy understanding, especially for the complex definitions. Because comments are removed during the complilation there is no limit to how many you can write. Be generous with your comments, write them with other developers in mind, using complete sentences to explain what’s going on.
SCSS Code Organization
- General pattern for the code organization. This pattern, once understood, lends iteslf to easy code reading, debugging, and extension.
.element-being-styled {
// 1. Default behavior rules for the element
// 2. Element's behavior at different resolutions
@media (breakpoint(tablet-narrow)) {
// Ideal order from mobile to desktop, but may differ based on definitions
// use either ascending or descending order for ease of reading and comprehension
}
// 3. Pseudo elements' definitions, if any
// Multiple pseudo elements should be listed in alpha order
&::after {
// 3a. Pseudo-elements' behavior at different resolutions
@media (breakpoint(tablet-narrow)) {
}
// 3b. Modifer classes as they apply to the pseudo element, avoid if possible
&.element-being-styled--active {
}
// 3c. Context for the elements, avoid this if possible
.parent-element & {
}
}
// 4. Element variants such as first or last child or state such as hover
&:hover,
&.js-active,
&:first-child,
&:last-child {
// 4a. Element state change at various resolutions
@media (breakpoint(tablet-narrow)) {
}
// 4b. The state change when the element-being-styled in context
// In rare cases, when an element with specific properties
// also needs to be restricted by context. Use with caution.
// Multiple parents should be listed in alpha order
.parent-class & {
// 4bi. Behavior of the tightly constrained element different resolutions
@media (breakpoint(tablet-narrow)) {
}
}
}
// 5. Element state with a custom class assigned
// This should be avoided if possible, however when coding in Luminate this is often needed
// For BEM code the modifier classes should be defined in a separate CSS block
&.element-being-styled--active & {
// 5a. Element state change at various resolutions
@media (breakpoint(tablet-narrow)) {
}
// 5b. Element custom behavior in context
// This should be avoided, if possible, as it brings in a lot of complexity
.parent-class & {
// 5bi. Element custom behavior in context at various resolutions
// This should be avoided, if possible
@media (breakpoint(tablet-narrow)) {
}
}
}
// 6. Element's styling when it appears in specific context
// Multiple parents should be listed in alpha order, so they are easy to locate
// For BEM code, the context should not be defined, rather a modifier class
// on an element-being-styled should be defined
// 6a. Grandparents; if there are multiple levels parents
// they should be all listed inline instead of nested for ease of reading.
// Regardless of the levels the blocks should be ordered by alpha
.gradnparent-class .parent-class & {
// 6ai. Behavior of the element-being-styled in context as specific resolutions
@media (breakpoint(tablet-narrow)) {
}
}
// 6b. Parent context can be set as follows
// Regardless of the levels the blocks should be ordered by alpha
.parent-class & {
// 6bi. Behavior of the element-being-styled in context as specific resolutions
@media (breakpoint(tablet-narrow)) {
}
}
// 6c. Preceding siblings are at times needed, they should be placed together with the
// parent and grandparent blocks in alpha order as the syntax is very similar
.sibling-element + & {
// 6ci. Behavior of the element-being-styled in context as specific resolutions
@media (breakpoint(tablet-narrow)) {
}
}
}
- Alphabetize all rulesets.
button,
.button {
// rules that start with a
background-color: palette('button', 'background');
border: 1px solid palette('button', 'border');
color: palette('button', 'text');
text-transform: uppercase;
z-index: 10; // rules that start with z
}
- Alphabetize all declaration blocks.
Note: for ease of finding elements in SASS, we ignore the first non-letter character in alphabetization.
// we ignore #, since all elements have child__ b is the first in order
#child__birthday {
order: 1;
}
.child__container {
display: flex;
}
.child__interests {
background-color: palette('child-interest' 'bg');
}
// photo is the last in the alphabetized list
.child__photo {
border: 1px solid palette('child-photo', 'border');
display: block;
}
- Whenever possible use classes to define styles. Based on the BEM principles the element with the same class should appear the same, regardless of the position. However, with an HTML rendered by the application, namely Luminate Online, that’s not always possible. Use ids and set context only if the standalone class option is not viable.
- The element that is being styled should always appear at the start of the line, the content should always be set inside only if absolutely necessary. This enables an easy tracking down of the styles for the element. This also simplifies code maintenance as addition and exception to the element styling will be easy to write without rewriting the code.
If we have the following HTML (based on an actual example)
<body class="donation donation--1620">
<div class="donation-levels">
<div class="donation-level">
<label for="donation-level-35">$35.00</label>
<input id="donation-level-35" type="checkbox" value="35" />
</div>
<div class="donation-level">
<label for="donation-level-45">$45.00</label>
<input id="donation-level-45" type="checkbox" value="45" />
</div>
<div class="donation-level donation-level--other">
<label for="donation-level-other">Other</label>
<input id="donation-level-other" type="text" value="" />
</div>
</div>
</body>
Styling of the donation levels will be as follows
// We are styling a label
label {
.donation-level & {
background-color: palette('donation-level', 'bg');
color: palette('donation-level', 'text');
padding: px-to-rem(10px) px-to-rem(20px);
}
// Here the label looks different on a form 1620
.donation--1620 .donation-level & {
background-color: palette('donation-level', 'bg-alt');
color: palette('donation-level', 'text-alt');
padding: px-to-rem(10px) px-to-rem(20px);
}
}
// We are styling an input
input[type="checkbox"] {
.donation-level & {
display: none;
}
}
To achieve the same styling the common way people write SCSS the code will look like this & will have to be studied first. Overwriting will also be difficult once more than 2-3 different rules will have to apply to the label or input.
DO NOT DO
// It's unclear what is being styled here without studying
.donation--1620 {
.donation-level {
label {
background-color: palette('donation-level', 'bg-alt');
color: palette('donation-level', 'text-alt');
padding: px-to-rem(10px) px-to-rem(20px);
}
}
}
// Not easy to see at a glace that it's the label we are styling
.donation-level {
label {
background-color: palette('donation-level', 'bg');
color: palette('donation-level', 'text');
padding: px-to-rem(10px) px-to-rem(20px);
}
}
- Minimize nesting in SCSS, there should be as few nestings as possible and never more than 3 levels deep.
- In cases where multiple levels of nesting required the following rules apply. In any styling tree there should be only one instance of
&selector
&selector &
and if necessary one@media
instance. Selectors should be combined into one line for ease of reading, rather than being stacked in a tree. Any SCSS definition tree should not be more than 3 levels deep. Pattern:
element{
&.element-classes {
}
&::pseudo-elements {
.parent-classes & {
@media (breakpoint(desktop-narrow)) {
color: black;
}
}
}
}
DO
label {
// Can easily tell at a glance that `::before` appears before the label
&::before {
.donation-level-user-entered & {
content: 'Enter Your amount';
}
.payment-type-option & {
content: '';
}
}
}
// Multiple selectors of the same level are combined, can be read and understood at a glance
label {
&.donation-level::before {
content: '$';
}
}
label {
// Label in the donation-level container (generic case)
.donation-level & {
background-color: palette('donation-level', 'bg');
color: palette('donation-level', 'text');
padding: px-to-rem(10px) px-to-rem(20px);
}
// Here the label looks different on a form 1620,
// a more complex case but can be read and understood fairly fast
.donation--1620 .donation-level & {
background-color: palette('donation-level', 'bg-alt');
color: palette('donation-level', 'text-alt');
padding: px-to-rem(10px) px-to-rem(20px);
}
}
DON’T DO
// Does ::before appear before the label or before
// donation-level-user-entered? Hard to tell at a glance.
label {
.donation-level-user-entered & {
&::before {
content: 'Enter Your amount';
}
}
.payment-type-option & {
&::before {
content: '';
}
}
}
// This requires a study and based on a compiler may be compiled in a way
// that may result in invalid CSS
label {
&.donation-level {
&::before {
content: '$';
}
}
}
label {
// Label in the donation-level container (generic case)
.donation-level & {
background-color: palette('donation-level', 'bg');
color: palette('donation-level', 'text');
padding: px-to-rem(10px) px-to-rem(20px);
// This big nesting is unnecessary as now the code has to be studied
// to identify which parent will be printed first.
// Understanding the inheritance will be difficult as well.
.donation--1620 & {
background-color: palette('donation-level', 'bg-alt');
color: palette('donation-level', 'text-alt');
padding: px-to-rem(10px) px-to-rem(20px);
}
}
}
Media Rules
- Media rules should be written within each element’s style definitions and not as one block or file. This patterns allows us to focus and style or debug any element at all resolutions in one place.
.logo {
line-height: px-to-rem($h1-font-size);
margin: 0;
width: 70%;
@media (breakpoint(tablet-narrow)) {
width: 50%;
}
@media (breakpoint(desktop-narrow)) {
width: 24%;
}
}
- All styles should be written with a mobile first approach.
- If the code is simpler when desktop first approach is used, write the rules using the desktop first approach.
// Here most the link looks the same on all resolutions,
// except a few styles on tablet & mobile, so the code is written
// in a desktop first approach
.menu__link {
font-size: px-to-rem(15px);
font-weight: bold;
line-height: px-to-rem(15px);
text-decoration: none;
text-transform: uppercase;
@media (breakpoint('under-desktop')) {
display: flex;
padding: px-to-rem($base-line-height / 2) 2%;
}
}
- In cases where the mobile and desktop display are drastically different feel free to put all styles into media breakpoints and not override multiple styles. Just ensure that you have full coverage for all breakpoints (0px to infinitely large screen).
// In this case the mobile menu has a lot of styles we don't need on desktop,
// so we only assign those styles to the appropriate breakpoints only.
.menu--main {
@media (breakpoint('under-desktop')) {
background: palette('menu', 'bg--mobile');
box-shadow: 0 5px 5px palette('menu', 'box-shadow--mobile');
display: none;
flex-direction: column;
width: 100%;
}
@media (breakpoint('desktop-narrow')) {
justify-content: space-between;
}
}
- Media rule should be the last innermost definition and should not contain any additional selectors inside.
DON’T DO
.form__column--80-100 {
@media (breakpoint('under-tablet-wide')) {
margin-bottom: px-to-rem($base-line-height / 4);
width: 100%;
&:last-child {
margin-bottom: 0;
}
}
}
DO
.form__column--80-100 {
@media (breakpoint('under-tablet-wide')) {
margin-bottom: px-to-rem($base-line-height / 4);
width: 100%;
}
&:last-child {
@media (breakpoint('under-tablet-wide')) {
margin-bottom: 0;
}
}
}
When the code is written according to the pattern it’s easy to extend, read and reason about. Here’s how this code can and should be extended with new style definitions.
.form__column--80-100 {
// Default element behavior
@media (breakpoint('under-tablet-wide')) {
margin-bottom: px-to-rem($base-line-height / 4);
width: 100%;
}
// Element behavior when it's a last child
// All logic for the last child goes into one block
&:last-child {
@media (breakpoint('under-tablet-wide')) {
margin-bottom: 0;
}
@media (breakpoint('tablet-wide')) and (breakpoint('under-desktop-wide')) {
border-bottom: 1px solid $grey;
}
.form--start-project & {
@media (breakpoint('under-tablet-wide')) {
margin-bottom: 10px;
}
}
.form--questionnaire & {
border-bottom: 1px solid $grey;
}
}
}
SCSS Variables
- All colors, font families, base font sizes, base line height sizes should be set in the _variables.scss file.
- All written code should rely on variables as much as possible.
- All background, text, and border colors should be set using the name-based map.
// in _variables.scss
$palettes: (
a: (
'text': $teal-dark,
'text--hover': $navy
),
)
// in _a.scss
a {
color: palette('a', 'text');
&:hover {
color: palette('a', 'text--hover');
}
}
- All breakpoints should be set using the predefinied breakpoints retrieved from the map.
// in _variables.scss
$breakpoints: (
'desktop-middle': 'min-width: 1024px',
'desktop-narrow': 'min-width: 960px',
'desktop-wide': 'min-width: 1200px',
'phone-landscape': 'min-width: 480px',
'phone-portrait': 'min-width: 320px',
'print': 'print',
'tablet-middle': 'min-width: 768px',
'tablet-narrow': 'min-width: 600px',
'tablet-wide': 'min-width: 800px',
'under-desktop': 'max-width: 959px',
'under-desktop-wide': 'max-width: 1199px',
'under-phone-landscape': 'max-width: 479px',
'under-tablet': 'max-width: 599px',
'under-tablet-wide': 'max-width: 799px'
);
// in _menu.scss
.menu--main {
@media (breakpoint('under-desktop')) {
background: palette('menu', 'bg--mobile');
box-shadow: 0 5px 5px palette('menu', 'box-shadow--mobile');
display: none;
flex-direction: column;
width: 100%;
}
@media (breakpoint('desktop-narrow')) {
justify-content: space-between;
}
}
SCSS Mixins & Placeholder Selectors
Mixins must be used with care, since they will render the repeated code when compiled. First evaluate if the same goal can be achieved with a placeholder selectors instead. The best use case of mixins is to generate a set of CSS rule sets that have various values for the same properties.
DO
@mixin colored-box($bg-color, $fg-color) {
background-color: rgba($bg-color, 0.8);
border: 1px solid $bg-color;
color: $fg-color;
}
.box {
border-radius: px-to-rem(0.25 * $base-line-height);
padding: px-to-rem($base-line-height);
width: 45%;
}
.box--green {
@include colored-box(palette('box--green', 'bg'), palette('box--green', 'text'));
}
.box--yellow {
@include colored-box(palette('box--yellow', 'bg'), palette('box--yellow', 'text'));
}
DO NOT DO
In this example, the code in the mixin will be printed out 3 times with only one variation. That means 10 identical rulesets will be rendered in CSS, making the file longer.
## _button.scss
// Generic styles, no opinions about colors
@mixin button(
$bg: palette('button', 'bg'),
$color: palette('button', 'text'),
) {
background-color: $bg;
border: 1px solid $bg;
color: $color;
cursor: pointer;
font-size: px-to-rem($base-font-size);
line-height: px-to-rem($base-line-height);
padding: px-to-rem($base-line-height / 8) px-to-rem($base-line-height / 2);
text-decoration: none;
-webkit-appearance: none;
&&::-moz-focus-inner {
padding: 0;
border: 0
}
}
button:not(.link),
.button {
@include button;
}
.button--danger {
@include button($black, $white);
}
## _input.scss
input[type='button'],
input[type='cancel'],
input[type='reset'],
input[type='submit'] {
@include button;
}
DO
In this example, the rulesets in the placeholder class %button
will be rendered once, but all the classes that extend placeholder class will be combined into one block, so the code will not have repetitions.
With globing enabled, and possibly compiler settings, the combined placeholder definition may be set lower in the file and thus hard to override. For those reasons, it’s best to create separate placeholder class for definitions that change, rather than put all properties into one placeholder class. If the same styles are defined for various elements, put placeholder class into a component with a name that’s starts with a letter in the begining of the alphabet, as the compiler may take things in order. Library is another possible play to put placeholder classes but they may be harder to locate there, the recommendation for that is to be determined.
A common use case, not overly complex.
## _button.scss
// Generic styles, no opinions about colors
%button {
cursor: pointer;
font-size: px-to-rem($base-font-size);
line-height: px-to-rem($base-line-height);
padding: px-to-rem($base-line-height / 8) px-to-rem($base-line-height / 2);
text-decoration: none;
-webkit-appearance: none;
&&::-moz-focus-inner {
padding: 0;
border: 0
}
}
// Set default color & styles, make it also a placeholder, so we can use it in other files
%button--default,
button:not(.link),
.button {
@extend %button;
background-color: palette('button', 'bg');
border: 1px solid palette('button', 'bg');
color: palette('button', 'text');
&:hover {
background-color: palette('button', 'bg--hover');
border-color: palette('button', 'bg--hover');
color: palette('button', 'text--hover');
}
}
// Define colors for custom inputs
// since the modifier class appears below the standard one inheritance will apply & override
.button--danger {
@extend %button;
background-color: palette('button--danger', 'bg');
border: 1px solid palette('button--danger', 'bg');
color: palette('button--danger', 'text');
&:hover {
background-color: palette('button--danger', 'bg--hover');
border-color: palette('button--danger', 'bg--hover');
color: palette('button--danger', 'text--hover');
}
}
## _input.scss
input[type='button'],
input[type='cancel'],
input[type='reset'],
input[type='submit'] {
@extend %button--default;
}
## _link.scss
.link--button {
@extend %button--default;
}
.link--text-button {
@extend %button;
}
More complex example with more placeholder class reuse.
## _button.scss
// Generic styles, no opinions about colors
%button {
cursor: pointer;
font-size: px-to-rem($base-font-size);
line-height: px-to-rem($base-line-height);
padding: px-to-rem($base-line-height / 8) px-to-rem($base-line-height / 2);
text-decoration: none;
-webkit-appearance: none;
&&::-moz-focus-inner {
padding: 0;
border: 0
}
}
// Set default color & styles, make it also a placeholder, so we can use it in other files
// this doesn't have to apply to buttons only
%button--default {
background-color: palette('button', 'bg');
border: 1px solid palette('button', 'bg');
color: palette('button', 'text');
&:hover {
background-color: palette('button', 'bg--hover');
border-color: palette('button', 'bg--hover');
color: palette('button', 'text--hover');
}
}
button:not(.link),
.button {
@extend %button;
@extend %button--default;
}
// Define colors for custom inputs
// since the modifier class appears below the standard one inheritance will apply & override
.button--danger {
@extend %button;
background-color: palette('button--danger', 'bg');
border: 1px solid palette('button--danger', 'bg');
color: palette('button--danger', 'text');
&:hover {
background-color: palette('button--danger', 'bg--hover');
border-color: palette('button--danger', 'bg--hover');
color: palette('button--danger', 'text--hover');
}
}
## _icon.scss
// if we want another element to match the colors of the button
.icon--default {
@extend %button--default;
}
## _input.scss
input[type='button'],
input[type='cancel'],
input[type='reset'],
input[type='submit'] {
@extend %button;
@extend %button--default;
}
## _link.scss
.link--button {
@extend %button;
@extend %button--default;
}
.link--text-button {
@extend %button;
}
SCSS Functions
Functions can be created and configured to retrieve values from a map. The starter kit includes the following functions.
- breakpoint for retrieving a breakpoint from a mapping.
- palette for retrieving a color from a mapping for a defined element.
- px-to-rem for converting pixels to rem units.
Style Reset
- When we write styles from scratch we normally use a
_normalize.scss
file to do some browser style resets that prevent the elements from appearing the same through the sites.
Browser Hacks
- Use only when necessary, please verify that you have implemented valid CSS first before adding any overrides.
- The use of
!important
is not allowed in the code, the CSS inheritance rules should be used to override styles. The only valid case for using!important
it to override an inline style produced by a third party system or another CSS definition with!important
in the third-party system that cannot be removed.
When to Define Styles for Generic Elements
New Site
Whenver we deploy a new site, either in Luminate, WordPress, or Drupal, our stylesheets should include definitions for all commonly used elements. These definitions must be set without any context. If the software generates it’s own CSS files, try to disable opinionated styles before trying to override them in SCSS with context.
When creating a new stylesheet, create also a style guide page with all generic HTML elements and ensure your styles apply to those elements. For the style guide, use the HTML code from snippets for generic text elements, form inputs, buttons, images, and tables, if in use.
Do not define styles for custom classes present in the style guide, they may be different in your site, the goal is to just style generic elements.
Existing Site or Existing Code
Review how the SCSS/CSS in the current site is implemented. If possible, as the client for the source code for the styles. If the request is to define new look & feel for generic elements, then proceed as we would with a new site. If the requiest is to change something that’s already defined or extend the definition, then extending the existing pattern is the best choice. One exception is if adding global definitions will not take too long or will be a sounder & simpler long term solution & then writing highly contextualized classes should be done.
When adding new stylesheet for Luminate, when the site loads another main CSS files, review the code and proceed with caution. Use _normalize.scss only if it doesn’t break existing layouts.
JavaScript Coding Standards
Use the Airbnb coding standards for all old and new JavaScript projects. A useful ES6 cheat sheet with new functionality.
All new Vue projects that are initialized with Vue CLI should use Vue CLI default coding standards. The main difference is that Prettify will by default set double quotes instead of single quotes. Your IDE should use the repository settings first before overriding them with global settings.
Additions to the Airbnb standards:
- Code readability is always the first priority. Most of the efficiency will be gained back by using automated code compression.
- When using jQuery link to the CDN version of jQuery, this may speed up page load if that file was already loaded on another site. Google is the preferred CDN.
- Do not mix the jQuery and non-jQuery objects. For ease of readability and future feature extensions and compatibility use jQuery objects. Make sure that jQuery selectors are optimal and efficient within the scope of jQuery.
- Variable name standards should follow the old Drupal pattern.
- See here for examples and information on jQuery coding standards and here for a useful cheatsheet.
- At the start of each function declare all variables used in a function in alphabetical order for ease of reference and readability. Then you can assign values and write out logical statements as necessary.
- Leave 1 empty line space between each function, that includes methods in Vue.js
- Leave 1 empty line space between objects with functions (data, computed, methods, ready, mounted, etc.) in Vue.js
- Use classes only for small utility classes, for everything else use functional model.
- Put each function into it’s own file for ease of reading and managing code. The files should generally be small, 100 lines or less. Only a few very complex cases would call for such long files. If your function is longer than 100 lines, see if it can be broken down into smaller functions. All values should be passed into each helper function via reference for clarity of scope, ease of reading, and ease of comprehension.
- Don’t write nested function, unless it’s absolutely necessary. The code is easier to read, comprehend and manage, when it’s broken out into small readable chunks.
DOimport handleInputDownChange from './handle-input-down-change'; import handleInputChange from './handle-input-change'; $numberInputDown.on('click', handleInputDownChange); $numberInput.on('input', handleInputChange);
DON’T DO
$numberInputDown.on('click', (e) => { const $inp = $(e.target) .parent() .siblings('.number-input'); $inp.val((i, oldVal) => (parseInt(oldVal, 10) > 0 ? parseInt(oldVal, 10) - 1 : oldVal)); calculateTotal(); }); $numberInput.on('input', (e) => { $(e.target).val((i, oldVal) => { let val = parseInt(oldVal, 10); let max = 0; const totalQuantity = getTotalQuantity(); const currentProduct = $(e.target).parents('.product')[0]; const oldQuantity = products.find(product => product.element === currentProduct).quantity; if (groupPriceAndDiscount) { max = products[0].maximumQuantity || Infinity; if (Number.isNaN(val) || val < 0) { val = 0; } else if (totalQuantity - oldQuantity + val > max) { val = max - getTotalQuantity(oldQuantity); } } else { max = $(e.target).parents('.product')[0].dataset.maximumQuantity || Infinity; if (Number.isNaN(val) || val < 0) { val = 0; } else if (val > max) { val = max; } } return val; }); calculateTotal(); });
- When writing functions for export give them the same name as with which they are imported. This makes reading and debugging unfamiliar code easier and faster.
Do
export default function backToTop() { ... }
import backToTop from './components/back-to-top';
DON’T DO
export default function () { ... }
import backToTop from './components/back-to-top';
JavaScript Naming Conventions
All variables, functions, methods and classes should have human-readable names and be descriptive of the functionality. Code readability is our top priority. The code will be compressed with automated processes for efficiency. Each routine should be placed into logical function or method for ease of readability and maintenance.
- Functions/methods/components: camelCase – the first letter is lower case, the first letter of each subsequent word is capitalized, no dashes, underscores or spaces
- Classes: PascalCase – the first letter is capitalized, the first letter of each subsequent word is capitalized, no dashes, underscores or spaces
- Static Variables/Constants: UPPERCASE
JavaScript Custom Event Naming Conventions
jQuery/JavaScript
All events that interact or possibly interact with jQuery should follow the event.namespace
format for ease of binding and unbinding of the events.
Plain JavaScript that will never interact with jQuery, Vue.js and other frameworks
The events will follow the camelCase
convention and have a name that starts with an action verb in the past tense to clearly communicate what happened. Ex: authenticatedUser
, initializedForm
, loggedOffUser
, resizedMenu
, clickedButton
, submittedForm
etc.