BBC's guide to development
  • General

    • About
    • Tools
    • Git(hub)
    • Showpad
    • Hosting
    • Maintenance
    • Security
    • Go live checklist
  • Front-end development

    • Bundlers
    • CSS/SCSS
    • Javascript
    • Vue
    • PHP
    • Mails
    • Dev Faq
  • Functions
  • Mixins
  • General

    • OOP Structure
  • Component Classes

    • Accordion
    • App
    • Component
    • HighwayApp
    • Popup
    • PNG Sequencer
    • Tab
  • Manager Classes

    • BountListenerMgr
    • Cache
    • Configuration
    • InViewStateMgr
    • Instance Manager
    • Event dispatcher
  • Factories

    • SwiperFactory
  • PDF

    • AssetLoader
    • BasePdfDoc
    • TemplatePdfDoc
    • CustomPdfDoc
  • Utility functions

    • canvas
    • Connection Status
    • css
    • dev
    • placeholder
    • dom
    • fetch
    • json
    • object
    • scroll
    • scrollbar
    • spreadsheets
    • string
    • url
  • General

    • ComponentMgr
    • ThreeJsViewer
  • Components

    • ComponentMgr
    • GltfModel
    • Snappable
    • Socket
    • ThreeJsViewer
    • ThreeJsViewerCamera
  • Loaders

    • ConfigurationSerializer
    • GltfBlockParser
  • Utils

    • CanvasInputAdapter
    • CollisionManager
    • SocketGridExpander
    • blender
    • headless
  • General

    • Troubleshooting
    • Legacy
  • Components

    • AssetBar
    • ConfigGenerator
    • ShowpadApp
  • Managers

    • Assets
    • AppsDb
    • Config
  • Utils

    • Connection Status
    • general
    • showpad-interactive
    • showpad-upload
  • Components

    • Accordion
    • BackButton
    • Breadcrumb
    • ByltButton
    • Hamburger
    • Icon
    • Logo
    • Loader
    • Modal
    • Popup
    • Prompt
    • ProgressBar
    • TextLoader
  • Composables

    • useDebugMode
    • useConnectionStatus
  • Utils

    • dom
    • props
  • General

    • General
    • Tracking
  • Components

    • Accordion
    • ActionButton
    • AssetItem
    • AssetList
    • BackButton
    • ConfigGenButton
    • Logo
    • Media
    • Modal
    • Popup
    • Prompt
    • SPButton
    • SPRouterView
    • SPTrackedRouterLink
    • TextLoader
    • View
  • Composables

    • useConnectionStatus
  • Stores

    • useAppsDbStore
    • useBreadcrumbStore
    • useShowpadAPIStore
    • useShowpadSDKStore
    • useSpConfigStore
    • useSpStore
    • useSpTrackingStore
  • The New Kit

    • General
    • Installation & Usage
    • ACF Blocks
    • PHPCS
    • Functions
    • Vite
    • WP Config
    • Staging Deployment
  • Best Practices

    • Page Structure
    • Fonts/Typography
  • Todo
GitHub
  • General

    • About
    • Tools
    • Git(hub)
    • Showpad
    • Hosting
    • Maintenance
    • Security
    • Go live checklist
  • Front-end development

    • Bundlers
    • CSS/SCSS
    • Javascript
    • Vue
    • PHP
    • Mails
    • Dev Faq
  • Functions
  • Mixins
  • General

    • OOP Structure
  • Component Classes

    • Accordion
    • App
    • Component
    • HighwayApp
    • Popup
    • PNG Sequencer
    • Tab
  • Manager Classes

    • BountListenerMgr
    • Cache
    • Configuration
    • InViewStateMgr
    • Instance Manager
    • Event dispatcher
  • Factories

    • SwiperFactory
  • PDF

    • AssetLoader
    • BasePdfDoc
    • TemplatePdfDoc
    • CustomPdfDoc
  • Utility functions

    • canvas
    • Connection Status
    • css
    • dev
    • placeholder
    • dom
    • fetch
    • json
    • object
    • scroll
    • scrollbar
    • spreadsheets
    • string
    • url
  • General

    • ComponentMgr
    • ThreeJsViewer
  • Components

    • ComponentMgr
    • GltfModel
    • Snappable
    • Socket
    • ThreeJsViewer
    • ThreeJsViewerCamera
  • Loaders

    • ConfigurationSerializer
    • GltfBlockParser
  • Utils

    • CanvasInputAdapter
    • CollisionManager
    • SocketGridExpander
    • blender
    • headless
  • General

    • Troubleshooting
    • Legacy
  • Components

    • AssetBar
    • ConfigGenerator
    • ShowpadApp
  • Managers

    • Assets
    • AppsDb
    • Config
  • Utils

    • Connection Status
    • general
    • showpad-interactive
    • showpad-upload
  • Components

    • Accordion
    • BackButton
    • Breadcrumb
    • ByltButton
    • Hamburger
    • Icon
    • Logo
    • Loader
    • Modal
    • Popup
    • Prompt
    • ProgressBar
    • TextLoader
  • Composables

    • useDebugMode
    • useConnectionStatus
  • Utils

    • dom
    • props
  • General

    • General
    • Tracking
  • Components

    • Accordion
    • ActionButton
    • AssetItem
    • AssetList
    • BackButton
    • ConfigGenButton
    • Logo
    • Media
    • Modal
    • Popup
    • Prompt
    • SPButton
    • SPRouterView
    • SPTrackedRouterLink
    • TextLoader
    • View
  • Composables

    • useConnectionStatus
  • Stores

    • useAppsDbStore
    • useBreadcrumbStore
    • useShowpadAPIStore
    • useShowpadSDKStore
    • useSpConfigStore
    • useSpStore
    • useSpTrackingStore
  • The New Kit

    • General
    • Installation & Usage
    • ACF Blocks
    • PHPCS
    • Functions
    • Vite
    • WP Config
    • Staging Deployment
  • Best Practices

    • Page Structure
    • Fonts/Typography
  • Todo
GitHub
  • Javascript

Javascript

Javascript guidelines are still a work in progress. But we already agree on some small rules.

Conventions

To keep things clean and smoothen out most points of confusion that may cause for frustrations and friction, there are some industry standard conventions we try to apply to our codebases. These are especially important for our kits as they will be reused throughout all our projects.

General

File structure

Files should be structured in folders according to their type

js/
  |
  |-- components/
  |-- factories/
  |-- managers/
  |-- utils/
  |-- MainApp.js
  • components: Contains the component classes, classes that represent and manage a DOM element.
  • factories: Contains the factory functions, functions that create and manage instances of other classes or generate new elements and data structures.
  • managers: Contains the manager classes, classes that add logic to the application purely in javascript
  • utils: Contains the utility functions, single function collections that add functionality to the application or website purely in javascript
  • MainApp.js: The main application class, the entry point of the application. This is the class that extends from the App class and is used to manage the lifecycle of the application.

Naming conventions

Following certain naming conventions helps to keep the developer working on the code informed about the type of variable they are working with.

Files should be named according to their purpose.

  • Simple variable names (e.g. strings, numbers, booleans, etc.) should be written in camelCase.
  • Object instances (aside from Object literals) should be written in PascalCase.
  • Static variables (e.g. constants, enums, etc.) should be written in UPPERCASE.
  • Boolean variables should always be prefixed with is- or has- depending on their context. It may be allowed to deviate from this rule, but these situations should be limited to an absolute minimum.
    • The is- prefix is used to indicate a state/mode of the subject the boolean tries to describe.

    • The has- prefix is used to indicate a presence of something inside the subject the boolean tries to describe.

      ✅ Do this❎ Don't do this
      var isVisible = truevar visible = true
      var hasError = falsevar error = false
      var isLoading = truevar loading = true
      var hasItems = truevar items = true
      var isEnabled = truevar enabled = true
      var isOpen = truevar open = true
      var hasItems = truevar items = true

Comparisons == vs ===

Always use === for comparisons.

if (value === otherValue) {
    // do something
}

The difference between == and === in JavaScript lies in how they compare values:

  • == is the loose equality operator. It compares two values for equality, but performs type coercion if the types are different. This means it tries to convert one or both values to a common type before comparing. As a result, == can lead to unexpected results, such as:
    0 == '0'           // true
    false == 0         // true
    null == undefined  // true
    '123' == 123       // true
    
  • === is the strict equality operator. It checks both value and type without performing any type conversion. Both sides must have the same type and value to be considered equal. For example:
    0 === '0'           // false
    false === 0         // false
    null === undefined  // false
    '123' === 123       // false
    1 === 1             // true
    

Why use ===? Using === is strongly preferred because it enforces more predictable and reliable comparisons, making your code less error-prone and easier to debug. The == operator can lead to subtle bugs caused by implicit type conversion, which can be hard to spot and fix.

In summary: always use === unless you have a specific reason to use == and understand its behavior completely.

DOM variables

Variables that contain a reference to a Element or NodeList should be prefixed with a dollar ($) sign. This informs the reader about the type of content the variable contains.

Arrays of DOM elements that are not NodeLists don't have a dollar sign since the actual variable is not a DOM related object, it is an Array containing DOM related objects.

// pure js variable
const notElement = 'value';

// DOM related variables
const $element = document.querySelector('.my-element');         // DOM Element
const $elements = document.querySelectorAll('.my-elements');    // NodeList

// pure variable that happens to contain Dom Variables as children.
const elements = Array.from($elements);

OOP Conventions

Quick set of rules for OOP:

  • Classes should be named in PascalCase
  • Filename and default exported class should be the same name.
  • Multiple classes allowed in single file, but only if for internal use. External use should be discouraged (unless put in separate files and exported as default).
  • Constructor parameters should be passed as single object.

General class structure

export default class MyClass {

    // constructor
    constructor (args = {}) {
        // constructor logic
    }

    // methods
    //...

    // getters & setters
    //...
}

// utilities
//...

// event listeners
//...

Private vs Public properties

When working with classes it is up to the developer of the class to make a distinction in which properties are considered private and which are considered public. Private properties attached to the scope of the class should be prefixed with an underscore (_) following the convention of other object oriented programming languages.

An underscore means that the property should not be accessed outside of the class instance. If in any case the property value should be readable but not writable, expose the private variable through a getter of the same name without the underscore. This way it can be seen but not overwritten.

Position getters & setters at the bottom of the class definition.

export default class MyClass {

    // constructor
    constructor (args = {}) {
        this.publicProperty = '';
        this._privateProperty = '';
    }

    // methods
    //...

    // getters & setters
    get privateProperty() {
        return this._privateProperty;
    }

    set privateProperty(value) {
        if (value === this._privateProperty) return;
        this._privateProperty = value;
    }

}

The current spec provides a way to apply private properties to a class instance by using the hashtag (#). But this poses some problems when using proxies, something Vue relies upon heavily (well explained by Lea Verou).

Check value before setting private property

Check the value before setting the private property to avoid unnecessary updates following the change made by the setter (unnecessary dom updates, re-renders, confusing events, etc.)

Constructor

Constructor parameters are passed as an object. This way there is no required order of passing values and no need to explicitly set null values when a parameter needs to be skipped.

export default class MyClass {

    // constructor
    constructor (args = {}) {
        this.prop1 = args.prop1;
        this._prop2 = args.prop2 ?? 'default value';
    }
}

Classes that manage a DOM element are required to put the element in a $el property of the class instance.

export default class MyClass {

    // constructor
    constructor (args = {}) {

        // put main DOM element in a private $el property of the class instance
        this._$el = args.$el;
    }

}

Extend from Component class to manage DOM elements

Extend from the Component class to manage DOM elements. Check the Component class for more information.

Private / Utility methods

Private and utility methods should be kept privately in the file, do not expose them to the outside world. These methods are not part of the public API of the class and should not be called from outside the class.

export default class MyClass {

    // constructor
    constructor (args = {}) {
        privateMethod.call(this);
    }

}

// util
function privateMethod() {
    console.log('private method');
}

Use call to keep the scope of the method

Use call to keep the scope of the method when calling it from within the class. This way the method will have access to the class instance and its properties.

Event handling

Listeners to events should be added to the bottom of the file and its logic should be kept to a minimum. Best practice is to use these methods to call other methods depending on type of event and or passed down data.

export default class MyClass {

    // constructor
    constructor (args = {}) {

        this._$button = args.$button;
        this._$button.addEventListener('onButtonClick', onButtonClick.bind(this));
    }

    // methods
    refresh() {
        // refresh logic
    }
    
    // getters & setters
    //...
}

// util
//...

// event listeners
function onButtonClick() {
    this.refresh();
}

Use bind to keep the scope of the method

Use bind to keep the scope of the method when calling it from within the class. Else functions called outside the class definition loose context (this will point to the global object).

Extend from EventDispatcher

Extend from EventDispatcher to automatically provide the class with event management out of the box. Check the EventDispatcher class for more information.

EventDispatcher comes with a BoundListenerMgr instance at this._blm that can be used to manage the listeners added to the class instance. Check the BoundListenerMgr class for more information.

import EventDispatcher from '@bbc/front-end-kit/js/managers/EventDispatcher';

export default class MyClass extends EventDispatcher {

    // constructor
    constructor (args = {}) {
        super();

        this._$button = args.$button;
        this._$button.addEventListener('onButtonClick', this._blm.add('onButtonClick', onButtonClick));
    }

    // methods
    refresh() {
        // refresh logic
    }

    destroy () {
        this._$button.removeEventListener('onButtonClick', this._blm.remove('onButtonClick'));
    }
}

// event listeners
function onButtonClick(e) {
    e.preventDefault();
    this.refresh();
}

Extending classes

When extending a class, make sure to call the parent constructor and pass down the arguments.

export default class MyClass extends ParentClass {

    // constructor
    constructor (args = {}) {

        // modify arguments before passing them to the parent constructor
        // setting a default value if custom property is not passed (possibly overriding the default value set in the parent class)
        args.customProperty = args.customProperty ?? 'default value';

        // pass down the arguments to the parent constructor
        super(args);

        // custom property now possibly processed by parent class(es)
    }

    // methods
    //...

    // getters & setters
    //...
}  

Call parent constructor

Call the parent constructor and pass down the arguments to ensure the parent class is initialized correctly.

Legacy

Older projects will not follow these rules yet. Try to understand the coding standards followed there and apply them only on that project.

Edit this page
Last Updated: 4/27/26, 12:56 PM
Contributors: Nicolas Jaenen