Skip to content
Mike Byrne edited this page Mar 8, 2023 · 7 revisions

A17 Behaviors

A framework for attaching JavaScript behaviors (interactions, events, manipulations) to DOM nodes.

AREA 17 has been using a form of data-behavior binding to JavaScript functions since 2012. Originally inspired by ElementalJS, introduced to us by Adam Berlin and John Barker.

The primary aims of "behaviors" are:

  • quickly and easily and clearly link JavaScript functions/interactions to DOM nodes
  • quickly and easily allow JavaScript code splitting
  • have a low learning curve
  • give some clear order to how to organise JavaScript DOM functions
  • work with a modular design system
  • doesn't require multiple if (targetNode) doThing() checks
  • make life easier

Behavior options, lazy behaviors, dynamically imported behaviors, set up and debugging options will all be covered in this wiki.

The library consists of 3 components:

  • manageBehaviors - the function that watches the DOM to load/unload behaviors
  • createBehavior - turns a structured object into a behavior
  • extendBehavior - extends a behavior with new or additional methods

General principle

manageBehaviors uses a MutationObserver to watch the DOM for changes, if it sees DOM nodes being added or removed with a specific data attribute, default data-behavior, then it will attempt to initialise or destroy a behavior linked to the specific DOM node.

Some key concepts:

Behavior collection methods

0.3.0+

The ability to add/remove auto clearing event listeners to a collection of DOM nodes, see Anatomy-of-a-behavior#behavior-collection-methods.

Extending behaviors

0.4.0+

The ability to import and extend one behavior, inside of another, see Extending a behavior.

Types of behaviors

Critical behaviors

These are behaviors imported into your main application JavaScript, that will be immediately available for initialisation, if required. Each included behavior will add to your initial application JavaScript size.

Dynamically imported

These are behaviors that are not included with the main application JavaScript and require Webpack to dynamically import them as they are required before initialising them. Once a behavior is loaded into memory, it will not be loaded again and so only file transfer per dynamic behavior will take place.

None lazy behaviors

When the corresponding DOM node(s) are detected with a data-behavior specified, then, if the behavior module is already loaded, the behavior will initialise, else an attempt to dynamically import the behavior before initialising will happen.

Lazy behaviors

These are behaviors that are only initialised when they are about to be in the viewport. Optionally they can be set to only trigger at a certain breakpoint range also. If the behavior module is already loaded, the behavior will initialise, else an attempt to dynamically import the behavior before initialising will happen. By default are linked to data-behavior-lazy elements.

Dynamic and Lazy behavior differences

Any behavior can be dynamically imported if it is not already loaded. Essentially, the element has data-behavior then the behavior(s) will be run as soon as the node is detected, if the element has data-behavior-lazy then the behavior(s) will only be run when the element is near the viewpoint. So, if the element has data-behavior and the behavior module is loaded, it will be run immediately, if the behavior module isn't loaded, it will be imported and then run. If the the element has data-behavior-lazy then the same process happens, only now it doesn't happen immediately but when the element gets close to being in the viewport.

So, if you wanted to lazy initialise a behavior on an element at the bottom of your page, but guarantee it would initialise immediately on being near the viewport without any delay, you import the behavior in your main application JavaScript bundle and use data-behavior-lazy. This way your application JavaScript would include the behavior module on page load.

If you wanted to lazy initialise a behavior and only load the behaviors JavaScript should it be needed, you would still use data-behavior-lazy and this time you would not include the behavior module in your application JavaScript, instead letting Webpack dynamically import it.