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
  • App

App

import App, { checkMediaQueries } from '@bbc/front-end-kit/js/components/App';

The App component provides a basic structure for every project to build upon. It extends Component. It sets a scope where instances can be managed with the InstanceManager and provides logic to quickly and easily hook into changes in viewport size during render. It also watches window resize and scroll events (directly and debounced)

Getting started

The App component is meant to be extended into a MainApp file for the project it will be used for. This setup allows to handle multiple apps within the webpage as well, if required. In that case it can be named anything else, although we advice to add the "App" suffix.

class MainApp extends App {

    // constructor
    constructor (args = {}) {

        // pass parameters to App component
        super(args);
    }

    // methods
    initReady(args) {
        // logic to run before and after the app can be set to a ready state
    }

    // other moethods
}

The class needs to be initialised in order to run in the desired container For a MainApp (only 1 app used throughout the project) the container can be the body of the page. In other cases it might be more desired to point to a specific DOM element within the body.

window.app = new MainApp({
    $el: document.body
})

Media queries

The app can automatically tell you in which predefine media query the app is running. In order to do so, media queries need to be defined in the constructor arguments before the app initializes.

The name property of the mediaquery definition will be used to call 2 possible hooks to use in the App class. Example: If the name is test then initTest and destroyTest.

Example using the _defaultsDeep method from Lodash to merge the querydefinitions into the constructor arguments. We create 2 media query definitions small and desktop.

  • small
    • Triggers when media enters or leaves (max-width: 50em)
    • calls initSmall on enter
    • calls destroySmall on leave
  • desktop
    • Triggers when media enters or leaves (min-width: 50em)
    • calls initDesktop on enter
    • calls destroyDesktop on leave
class MainApp extends App {

    // constructor
    constructor (args = {}) {

        // add mediaquery definitions to args
        super(_defaultsDeep(args, {
            mediaQueries: [
                { name: 'small',        query: '(max-width: 50em)' },
                { name: 'desktop',      query: '(min-width: 50em)' }
            ]
        }));
    }

    // methods
    initReady(args) {
        // logic to run before and after the app can be set to a ready state
    }

    // methods that will be called when media queries hit or exit
    initSmall(args) {

    }

    destroySmall(args) {

    }

    initDesktop(args) {

    }

    destroyDesktop(args) {

    }
}

Every method in the class receives an args object with bits of information about the context in which it is being called. With this information it provides us the freedom to easily alter the outcome of the function.

Properties it contains:

  • mq: The media query match object which is used internally to decide if the init or destroy should run
  • type: The type of action that needs to take place
  • event: A key that represents some type of event that might've triggered the method (in this case it can be init or resize)
  • key: A shorthand identifier made of joining type and event together with :, example: destroy:resize.

As mentioned before, this is not very usefull when directly extending from App, but comes in very handy when extending from other classes that in turn extend from this app as they will probably pass extra information through the args object to further inform the developer about the context in which the method was triggered.

Apps that extend from App are:

  • HighwayApp: Adds highway integration to the class
  • ShowpadApp: Adds Showpad integration to the class (by extending Highway App)

Instance manager

App class also provides a InstanceManager instance by default so that initialisations of instances can be done very quickly with the least amount of code possible. This helps to keep the file clear and bugfree in small to very large projects.

The instance is saved in the scope on the private variable _instances but is also accessible through the public getter instance

    // methods
    initReady() {
       this.instances.init('key', 'selector', Class)

       // init hero component
       this.instances.init('heroes', '.hero', Hero);
    }

Extra methods

As mentioned before, App provides methods out of the box that are triggered on the scroll and resize window events. These can be added in the same scope as the query methods

Note

These methods don't need to be defined in the MainApp file when they are nog used by the project. They're just there in case we need them.

Add them only when required. Keep the MainApp as short and clean as possible

class MainApp extends App {

    // constructor
    constructor (args = {}) {

        // pass parameters to App component
        super(args);
    }

    // methods
    initReady() {
        // logic to run before and after the app can be set to a ready state
    }

    // window methods
    resize () {

    }

    scroll () {

    }
}

But these methods are fired instantly. For better performance it is best practice to debounce these events in order to avoid glitching of the window. These are also provided by the App class. For both resize and scroll methods, the app provides 2 debounce method types:

  • debounce: The classic way of debouncing events, sets a timer the moment the event is fired. When fired it waits 100ms and bundles all the same events that are fired within that time as 1 event when the timer ends.
  • delayed: Slightly different to debounce in that it resets the timer every time the event is called within the waiting period.
class MainApp extends App {

   // constructor
   constructor (args = {}) {

       // pass parameters to App component
       super(args);
   }

   // methods
   initReady() {
       // logic to run before and after the app can be set to a ready state
   }

   // window methods
   resize () {

   }

   debouncedResize () {

   }

   delayedResize () {

   }

   scroll () {

   }

   debouncedScroll () {

   }

   delayedScroll () {

   }
}

API

constructor (args = {})

The constructor method initialises the new App instance.

Parameters

  • args: The configuration object used by the constructor to initialise the App in the desired way.
    • $el: The root DOM element for this App instance. Passed through to Component.
    • mediaQueries: The mediaquery definition collection it needs to initialise for

Methods

init[MediaQueryName] (args = {})

The method that will be called when the media query of the same name is activated. (Replace [MediaQueryName] with a PascaleCase version of the media query definition, "ready" => "initReady()"). These will be created for every mediaquery definition.

Parameters
  • args: The configuration object used by the constructor to initialise the Popup in the desired way.
    • mq: The media query match object which is used internally to decide if the init or destroy should run
    • type: The type of action that needs to take place
    • event: A key that represents the event that triggered the method ('init', 'resize', or 'scroll')
    • key: A shorthand identifier made of joining type and event together with :, example: destroy:resize.

destroy[MediaQueryName] (args = {})

The method that will be called when the media query of the same name is activated. (Replace [MediaQueryName] with a PascaleCase version of the media query definition, "ready" => "destroyReady()")

Parameters
  • args: The configuration object used by the constructor to initialise the Popup in the desired way.
    • mq: The media query match object which is used internally to decide if the init or destroy should run
    • type: The type of action that needs to take place
    • event: A key that represents the event that triggered the method ('init', 'resize', or 'scroll')
    • key: A shorthand identifier made of joining type and event together with :, example: destroy:resize.

resize ()

Method that will be called the moment the window resize event is triggered by the borwser window.

debouncedResize ()

Resize are debounced automatically, when the debounce timer hits, it calls this method. Use this in favor of resize to optimize performance when resizing.

delayedResize ()

Works almost like debouncedResize but resets the timer every time the resize event is triggered. Great for performance but may cause some visual glitches it the user keeps resizing the window as inits and destroy will wait until after the user starts triggering the events.

scroll()

Method that will be called the moment the window scroll event is triggered by the borwser window.

debouncedScroll ()

Scroll are debounced automatically, when the debounce timer hits, it calls this method. Use this in favor of scroll to optimize performance when resizing.

delayedScroll ()

Works almost like debouncedScroll but resets the timer every time the scroll event is triggered. Great for performance but may cause some visual glitches it the user keeps resizing the window as inits and destroy will wait until after the user starts triggering the events.

Exported methods

Exported methods are methods that come along with the class, but still need to be imported when used. They'll be able to run stand-alone but may need a scope to work with. There is a high change the default exported class is actually using that exported method internally.

checkMediaQueries(args = {}, options = {})

This methods check all the mediaqueries within the scope it is run in (looks for this._mediaQueries). It will descide which mediaquery-related method of the given scope should be run depending on the media query information stored in the same scope depending on the matchMedia state change.

Note

checkMediaQueries is called on both resize and scroll window events. The event key passed to your media-query hooks reflects the actual event type ('resize' or 'scroll').

Parameters
  • args: Configuration object to influence the operations of the function
    • type: populates the type property of the object that will be passed to the mediaquery-related method
    • event: populates the event property of the object that will be passed to the mediaquery-related method
    • force: Will force the mediaquery related method to run eventhough the matchMedia state wasn't changed.

Note

Both type and event will be used to create the key property of the object that will be passed to the mediaquery-related method.

Private properties

The App class uses some private properties that will be present in the scope of your app class but aren't really meant to be accessed directly.

_instances

The property where the instance manager is kept in memory. The instances getter will return the instance kept there.

this._instances = new InstanceMgr({
    $parentNode: this._$el
});

_debouncers

The property where the debounce timers are stored. When the value of a debounce property equals null, it means there is not timer running at that moment.

this._debouncers = {
    resize: {
        timers: {
            debunce: null,
            delay: null
        }
    },
    scroll: {
        timers: {
            debunce: null,
            delay: null
        }
    }
}

_mediaQueries

An array of mediaquery definitions.

this._mediaQueries = [
    { name: 'ready',        query: '(min-width: 0em)' },
    ...(args.mediaQueries || [])
];

It will always contain at least the 'ready' definition so that initReady can be called out of the box. Using initReady ensures the developer that all the super constructors had had their time to run before the custom logic is fired for the project.

External dependencies

This class uses some external dependencies that may be necessary to install using NPM.

  • lodash: For some quick and useful utility methods like:
    • camelCase: To build method names like initSmall and destroyDesktop from the media query name property

Todo

  • Provide raw API documentation
Edit this page
Last Updated: 4/27/26, 12:56 PM
Contributors: Nicolas Jaenen