Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

passive-events-support

Package Overview
Dependencies
Maintainers
1
Versions
33
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

passive-events-support

Passive Events Support

  • 1.1.0
  • latest
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
2.2K
decreased by-30.62%
Maintainers
1
Weekly downloads
 
Created
Source

Passive Events Support

Introduction

The Issue

How many times have you yourself forgotten to make an event listener as passive, or installed a library such as Bootstrap, jQuery or Materialize and suddenly in the Google Chrome you see:

[Violation] Added non-passive event listener to a scroll-blocking 'touchstart' event. Consider marking event handler as passive to make the page more responsive.

Or when running Lighthouse you get a lower score with a message:

Does not use passive listeners to improve scrolling performance

Consider marking your touch and wheel event listeners as passive to improve your page's scroll performance.

What's a passive option?

According to Official Documentation a passive option is:

A boolean value that, if true, indicates that the function specified by listener will never call preventDefault(). If a passive listener does call preventDefault(), the user agent will do nothing other than generate a console warning.

Why is it necessary?

It is well docummented that:

According to the specification, the default value for the passive option is always false. However, this introduces the potential for event listeners handling certain touch events (among others) to block the browser's main thread while it is attempting to handle scrolling, resulting in possibly enormous reduction in performance during scroll handling.

See Improving scrolling performance with passive listeners to learn more.

The solution

Making event listeners as passive manually could be a repetetive and time consuming experience. Also if caused by a 3rd party, modifying it's source code should never be an option!

Here comes the Passive Events Support package! This is the package that will help you debug the source, solve the issue, but also improve the performance. It is flexible and highly configurable package!

How it works

When event listener does not have a passive option, it will be added and its value will depend on whether preventDefault() is being called in the handler or not.

When event listener is not calling preventDefault() and passive option is not passed, it will add a { passive: true }

element.addEventListener('touchstart', (e) => {}) // { passive: true }

When event listener is calling preventDefault() and passive option are not passed, it will add a { passive: false }

element.addEventListener('touchstart', (e) => { e.preventDefault() }) // { passive: false }

When passive or other option is passed, their values will not be overwritten

element.addEventListener('touchstart', handler) // { passive: true }
element.addEventListener('touchstart', handler, { passive: false }) // { passive: false }
element.addEventListener('touchstart', handler, { capture: true) // { capture: true, passive: true }
element.addEventListener('touchstart', handler, { capture: false, passive: false }) // { capture: false, passive: false }

Installation

yarn add passive-events-support

Usage

This package must be imported before any package or code that is causing an issue or Lighthouse warning.

// With JS
import { passiveSupport } from 'passive-events-support/src/utils'
passiveSupport({/*...*/})
<!-- With HTML -->
<script>
  window.passiveSupport = {/*...*/}
</script>
<script type="text/javascript" src="node_modules/passive-events-support/dist/main.js"></script>

By default, importing this package will not update non-passive event listeners. For this package to act, you must specify which event listeners should be made as passive. See the Configuration section below.

Configuration

It is highly recommended to configure and only pass the custom list of event listeners, that trigger the console or Lighthouse warning.

Configurable Options

OptionTypeDefault
debugbooleanfalse
eventsarray[]
listenersarray[]

Option: debug

When enabled, all the non-passive event listeners will be console logged.

{
  debug: true
}

Console output

[Passive Events Support] Non-passive Event Listener
  element: div.some-element
  event: 'touchstart'
  handler:
    fn: ƒ (e)
    fnArgument: 'e'
    fnContent: 'console.log(e)'
    fnPrevented: false
  arguments: false
  updatedArguments: { passive: true }

The updatedArguments parameter will be shown only if the event listener was updated by this package.

Option: events

The list of events whose event listeners will have a passive option assigned with the value of true or false decided by the package as it is documented in the How It Works section.

Supported Events:
TypeEvents
Touchtouchstart, touchmove, touchenter, touchend, touchleave
Wheelwheel, mousewheel
{
  events: ['touchstart', 'touchmove']
}

Events that are not supported will be ignored.

Known events option issue:

While this option enables the package to assign the correct passive option value to all the event listeners for the listed events it also might break certain event listeners. The issue appear when preventDefault() is not being called from the handler itself, but rather from the another method called by the handler. In this case this package loses the track of preventDefault() and it marks the event listener as passive. This causes the event listener to break prompting an error message:

Unable to preventDefault inside passive event listener invocation.

Luckilly, this can easilly be debugged in debug mode and fixed by the listeners configuration option!

With this option, instead of certain events, you target certain event listeners.

When working altogether with events option, this option could be used to fix the event listeners broken by events option.

{
  listeners: [
    {
      element: '.select-choice',
      event: 'touchstart',
      prevented: true // (optional) will force { passive: false }
    },
    {
      element: '.select-choice',
      event: 'touchmove'
    }
  ]
}

When prevented option is not presented, the package will calculate the passive value automatically as it is documented in the How It Works section.

Events that are not supported will be ignored. See supported events list.

Browser Support

Even tho the passive option is not supported by all the browsers (see Browser compatibility), this package, by default, checks the browser support for passive option before assigning it.

Debugging the browser support

You can yourself access the variable indicating the support:

// With JS
import { passiveSupported } from 'passive-events-support/src/utils'
console.log(passiveSupported())
<!-- With HTML -->
<script type="text/javascript" src="node_modules/passive-events-support/dist/main.js"></script>
<script>
  console.log(window.passiveSupported)
</script>

Manually assigning the passive option

You, just like this package, yourself can manually add the passive option:

// use window.passiveSupported if imported with <script>
element.addEventListener('tocuhstart', handler, passiveSupported() ? { passive: true } : false)

FAQs

Package last updated on 23 May 2023

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc