GithubHelp home page GithubHelp logo

inert's Introduction

The inert attribute/property allows web authors to mark parts of the DOM tree as inert:

When a node is inert, then the user agent must act as if the node was absent for the purposes of targeting user interaction events, may ignore the node for the purposes of text search user interfaces (commonly known as "find in page"), and may prevent the user from selecting text in that node.

Furthermore, a node which is inert should also be hidden from assistive technology.

Details

Polyfill

Installation

npm install --save wicg-inert

We recommend only using versions of the polyfill that have been published to npm, rather than cloning the repo and using the source directly. This helps ensure the version you're using is stable and thoroughly tested.

This project provides two versions of the polyfill in package.json.

  • main: Points at dist/inert.js which is transpiled to ES3.
  • module: Points at dist/inert.esm.js which is transpiled to ES3.

If you do want to build from source, make sure you clone the latest tag!

Usage

1. Either import the polyfill, or add the script to your page

import "wicg-inert";

OR…

    ...
    <script src="/node_modules/wicg-inert/dist/inert.min.js"></script>
  </body>
</html>

2. Toggle inert on an element

const el = document.querySelector('#my-element');
el.inert = true; // alternatively, el.setAttribute('inert', '');

Legacy Browser Support

If you want to use inert with an older browser you'll need to include additional polyfills for Map, Set, Element.prototype.matches, and Node.prototype.contains.

In accordance with the W3C's new polyfill guidance, the inert polyfill does not bundle other polyfills.

You can use a service like Polyfill.io to download only the polyfills needed by the current browser. Just add the following line to the start of your page:

<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=Map,Set,Element.prototype.matches,Node.prototype.contains"></script>

Strict Content Security Policy

By default, this polyfill will dynamically insert some CSS, which requires the style-src rule of your Content Security Policy to allow 'unsafe-inline'.

It is possible avoid doing so by including those rules from a CSS stylesheet, as follows (the id property is used by the polyfill to know if it needs to dynamically add the missing rules):

<link rel="stylesheet" type="text/css" href="inert.css" id="inert-style" />

The stylesheet should include the following rules:

[inert] {
  pointer-events: none;
  cursor: default;
}

[inert], [inert] * {
  user-select: none;
  -webkit-user-select: none;
  -ms-user-select: none;
}

Performance and gotchas

The polyfill attempts to provide a reasonable fidelity polyfill for the inert attribute, however please note:

  • It relies on mutation observers to detect the addition of the inert attribute, and to detect dynamically added content within inert subtrees. Testing for inert-ness in any way immediately after either type of mutation will therefore give inconsistent results; please allow the current task to end before relying on mutation-related changes to take effect, for example via setTimeout(fn, 0) or Promise.resolve().

    Example:

const newButton = document.createElement('button');
const inertContainer = document.querySelector('[inert]');
inertContainer.appendChild(newButton);
// Wait for the next microtask to allow mutation observers to react to the
// DOM change
Promise.resolve().then(() => {
  expect(isUnfocusable(newButton)).to.equal(true);
});
  • Using the inert property, however, is synchronous.

  • The polyfill will be expensive, performance-wise, compared to a native inert implementation, because it requires a fair amount of tree-walking. To mitigate this, we recommend not using inert during performance sensitive actions (like during animations or scrolling). Instead, wait till these events are complete, or consider using requestIdleCallback to set inert.

Testing

Tests are written using ES5 syntax. This is to avoid needing to transpile them for older browsers. There are a few modern features they rely upon, e.g. Array.from and Promises. These are polyfilled for the tests using Polyfill.io. For a list of polyfilled features, check out the polyfill section in karma.conf.js.

Big Thanks

Cross-browser Testing Platform and Open Source <3 Provided by Sauce Labs

inert's People

Contributors

aomarks avatar bkardell avatar clearlyclaire avatar dependabot[bot] avatar dontcallmedom avatar dpogue avatar edg2s avatar estelle avatar francescostella avatar goatandsheep avatar greenkeeper[bot] avatar igoradamenko avatar jakechampion avatar krolow avatar malvoz avatar marcoscaceres avatar martellienrico avatar nertzy avatar patrickjs avatar robdodson avatar saschanaz avatar straker avatar timbomckay avatar valdrinkoshi avatar vinicius-casarin avatar y-a-v-a avatar yoavweiss avatar zhenyanghua avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

inert's Issues

Version 10 of node.js has been released

Version 10 of Node.js (code name Dubnium) has been released! 🎊

To see what happens to your code in Node.js 10, Greenkeeper has created a branch with the following changes:

  • Added the new Node.js version to your .travis.yml

If you’re interested in upgrading this repo to Node.js 10, you can open a PR with these changes. Please note that this issue is just intended as a friendly reminder and the PR as a possible starting point for getting your code running on Node.js 10.

More information on this issue

Greenkeeper has checked the engines key in any package.json file, the .nvmrc file, and the .travis.yml file, if present.

  • engines was only updated if it defined a single version, not a range.
  • .nvmrc was updated to Node.js 10
  • .travis.yml was only changed if there was a root-level node_js that didn’t already include Node.js 10, such as node or lts/*. In this case, the new version was appended to the list. We didn’t touch job or matrix configurations because these tend to be quite specific and complex, and it’s difficult to infer what the intentions were.

For many simpler .travis.yml configurations, this PR should suffice as-is, but depending on what you’re doing it may require additional work or may not be applicable at all. We’re also aware that you may have good reasons to not update to Node.js 10, which is why this was sent as an issue and not a pull request. Feel free to delete it without comment, I’m a humble robot and won’t feel rejected 🤖


FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Able to focus an ostensibly inert input in Safari

Update: Most of this issue was just browsers being browsers (I didn't realize how much tab key behavior varies), but one real problem remains: In Safari, pressing tab can sometimes focus and allow interacting with elements that should be inert.

For example, on https://wicg.github.io/inert/demo/, clicking on the page and then pressing tab focuses an input that should be inert. I can send exactly one keypress to that input, but typing further has no effect.
inert-safari
(Safari 12.1.1 on MacOS 10.13)

leverage ShadowDOM v1 + tabindex=-1 for inertness

From step 3 of https://w3c.github.io/webcomponents/spec/shadow/#sequential-focus-navigation

[...] an element whose tabindex value is negative must not be appended to NAVIGATION-ORDER.

Which in other words means that if an element has tabindex=-1 and a shadowRoot, the focus won't be able to reach the element's contents (distributed or not) 🎉

The inert polyfill could leverage this behavior for a faster performance, e.g. just set the tabindex to elements that have a shadowRoot w/o traversing them.

Another (more invasive) way to achieve inertness is to set a shadow root to the top element to be inerted, without traversing its content, e.g.

el.setAttribute('tabindex', -1);
if (!el.shadowRoot && el.attachShadow) {
  el.attachShadow({mode: 'open'}).appendChild(document.createElement('slot'));
}

Update: it is still possible to programmatically focus the content (e.g. el.querySelector('button').focus()), so we might still need to traverse the content to override focus

@alice @robdodson WDYT?

Browser vendor feedback

Jotting down some feedback we've received while discussing inert with other implementors:

Mozilla

"Inert is something I think is useful but it has more of an 'implement at some point' status... once the spec has more details."

@dbolter would you be able to expand a bit on what details you think are currently missing from the spec?

Safari

Reached out but unable to get comment.

Edge

We had a lengthy discussion with Edge. My best attempt at a summary is:

  • Edge wondered if inert wouldn't be better served as a CSS property, instead of an HTML attribute. It could be similar to, or maybe even a part of, visibility.
/* Keyword values */
visibility: visible;
visibility: hidden;
visibility: collapse;
visibility: inert; 

Edge wondered if this would obviate the need for something like <dialog> because visibility allows subtree children to "escape" and display even if their parent is visibility: hidden. Example:

<main style="visibility: inert"> <!-- everything in main is "inerted" -->
  ...
  <div class="modal-dialog" style="visibility: visible"> <!-- this child overrides the parent and is "un-inerted">
  • Edge stated they were not opposed to us continuing to work on inert as an attribute/property, or even shipping it behind a flag for experimentation, but suggested we also more thoroughly explore and explain its interaction (if any) with CSS. Some of this work has already been done in the Wouldn't this be better as...? section.

cc @boggydigital, @travisleithead, @dbolter, @nt1m, @cookiecrook, @alice to make sure I captured everyone's positions accurately. BTW thank you all for taking the time to discuss this with us 😊

`Let` not yet supported in strict mode in Safari 9

I'm getting an error in Safari 9.1.1 when I include the inert.js file. I want to test dialogs with Voiceover, which is how I ran into this issue.

Here's the error:

inert.js:93 
SyntaxError: Unexpected use of reserved word 'let' in strict mode

I saw some stuff in another issue about transpiling for other browsers. Do I need to do anything special with the polyfill to get it to work with Safari?

Thanks 😺

Inert property not synchronous for NVDA+Chrome

I'm not sure whether this is a bug per se but I wanted to inform you because it contradicts the documentation provided in the readme:

Using the inert property, however, is synchronous.

Looking at this code example:

     // Remove inert of next section
     nextSection.inert = false;
     // Focus first input in next section
-    this.focusFirstInput(nextSection);
+    setTimeout(() => {
+      this.focusFirstInput(nextSection);
+    }, 5);

For some reason, pressing Space on the button that triggered this code worked properly in Chrome with NVDA, but triggering it with Enter did not. After adding a short timeout, both the Space and Enter keys work as expected. Both Space and Enter worked without the timeout in VoiceOver+Safari.

Screen reader virtual cursor reads controls

Hi, I experience this issue with inert:

once inert is added it prevents controls from being focused, but it still possible to navigate to controls inside an element with inert with a screen reader virtual cursor and use them (see screenshot).

Is it planned to be so and if yes what can be a solution to totally prevent elements inside inert from being clicked? I only can think of adding aria-hidden for all the controls which doesn't seem a good idea.

virtual-cursor

[Firefox] Inert scrollable nodes

Firefox will add to the tab order nodes with overflow: auto|scroll and enough content to be scrollable (this is done so the user can scroll the contents with the keyboard) - see http://jsbin.com/kupijuj/1/edit?html,output.
The polyfill should take this into account by setting tabindex=-1 to such elements, otherwise there will be an extra tab for each of such nodes.

An in-range update of rollup is breaking the build 🚨

Version 0.53.3 of rollup was just published.

Branch Build failing 🚨
Dependency rollup
Current Version 0.53.2
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

rollup is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • continuous-integration/travis-ci/push The Travis CI build could not complete due to an error Details

Commits

The new version differs by 10 commits.

  • 1ceb6bc 0.53.3
  • bd73067 Update changelog
  • bdd8438 Merge branch 'no-explicit-external-warnings' into release-0.53.3
  • 9c32ad8 Merge branch 'guybedford-reexport-aliasing-bug' into release-0.53.3
  • e75a487 0.53.2
  • 9922dbe Update changelog
  • 713ea76 Removes errors when output options is an array.
  • 9b5bc4e include fix
  • 546a4aa failing test case
  • 8ef29d8 disable unresolved import warnings when resolve explicitly returns false

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Please add license file and contributing file

To help avoid IP and code provenance issues, please consider adding in a contributor agreement / CLA. This will help consumers that have more rigid IP policies for consuming third-party libraries - like the Eclipse foundation for example.

It could be as simple as adding the contributing.md file in the root of the repo with the following content:

A CLA is a document that specifies how a project is allowed to use your code. We want a CLA that is simple and as clear as possible so that it doesn't disrupt contributions.
When you make a contribution to the project, you agree:

The code you wrote is your original work (you own the copyright) or you otherwise have the right to submit the work.
You grant the project a nonexclusive, irrevocable license to use your submitted code in any way.
You are capable of granting these rights for the contribution.
By submitting a fix you agree to the above statements.

It would also be useful to have a license (or license.md) file so that folks don't need to search the repo to find the license.

Un-inert doesn't remove tabindex=-1 if inert was applied to elements, which was selected by *

I tried to apply inert attribute to all child elements of certain node, using selector like '.main '. it adds inert attribute to all elements in dome under .main node, also this adds tabindex and aria-hidden. But when I remove inert by using selector '[inert]' and removeAttribure - inert and aria-hidden attribute are removed, but tabindex keeps in elements, and elements can't be focused.

All works if I use specific selector like '.main span' or '.main .links'.
Looks like * selector broke inert polyfill or it can't work with elements, which was getting bu such selector.

Calling `blur()` triggers recalc style

I think Sam pointed this out during our perf audit as an issue. I'm not sure if we can avoid calling blur, but maybe we can if we have a way to cheaply determine that nothing in the inert subtree is the current activeElement

can inert.html be an import of the script?

Ideally I'd like to install the inert dependency and use inert.html to import the polyfill, e.g.

<link rel="import" href="/bower_components/inert/inert.html">

Can inert.html be updated to only import the inert polyfill? Its current content can be moved to a new file index.html or demo/index.html

@alice @robdodson WDYT?

accesskey should not function on inert content

If accesskey is specified on content which is inert it should be ignored. Currently if I add an accesskey on the checkbox in the demo pages, then I can check it using the accesskey even if it is inert.

Setting .inert property doesn't work if script is async

If inert.js is loaded as <script src="inert.js" async> and I select an element and set its .inert=true property before the script has had a chance to load, that inert property will not get picked up by the initial pass in _onDocumentLoaded. I believe you must use the inert attribute, instead of the property, for initial setup, if you're loading the script async.

Would it be possible to inspect to see if an element has set its inert property when we patch the prototype? If not, we may want to indicate in the docs that this is a gotcha.

cc @alice @paullewis

IE10 issues

Hi there

I've come across a couple issues when testing in IE10

When making the subtree unfocusable, it throws an error on some HTML tags as it doesn't support the contains method. Those objects being SVGs and comments.

I've just made a workaround (not that nice) to test for invalid tags.

var invalidTags = ['undefined', 'svg'];

if (!invalidTags.indexOf(startNode.tagName)) {
     if (startNode.contains(activeElement)) activeElement.blur();
}

Also, IE10 doesn't support pointer-events - I've had to use Modernizr to test for pointer events, then add a class if not supported so it adds visibility:hidden to inert elements. As I typically use inert for off-page/hidden objects, it's worked OK for me.

Why not have sub tree not-inert id specified?

Why can we not set inert=false on an element under an inert element. Here is a simple example when this could be useful:

Full Screen Menu

If I had the follwing html

<body>
<main>
My Main content
There are focusable elements in here
<aside>
My sidebar
There are also focusable elements in here
</aside>
<nav>
This is a full screen menu with focusable links
</nav>
</body>

When the Full Screen Menu is activated, I would like everything except the menu to become inert. I know that in this simple example, setting inert on the main and the asside isn't that diffictult but it would be much easier to set inert=true on the body element then inert=false on the nav element.

Issues when document.body is null?

In another round of mysterious errors...

I've seen some cases where it looks like the mutationobserver is trying to be set up before the DOM is ready.

I'm seeing the error with this line:

this._observer.observe(this._document.body, { attributes: true, subtree: true, childList: true });

Errors returned: "TypeError: Argument 1 of MutationObserver.observe is not an object."

It's happened in FF 55,56 on Linux, Mac and Windows as well as IE 11 and Edge.

It looks like the readyState checking all makes sense, so I'm not sure what's the cause yet.

inert polyfill breaks build processes that use phantomJs

PhantomJS 1.9.8 (Mac OS X 0.0.0) ERROR
  ReferenceError: Can't find variable: Map
  at /Users/runtimeZero/code/app/client/vendor/inert/inert.min.js:589

The use of Map doesnt go well with PhantomJS. Is there any solution available for this ?

Removing inert does not maintain elements previous aria-hidden state

If this is the element to inert

<button aria-hidden=true>Click</button>

When you inert the element and then remove the inert attribute, the aria-hidden attribute is also removed.

The aria-hidden state should probably be saved just like the tabindex so it can be properly restored.

Use `:disabled` instead of `[disabled]`, check for `contenteditable="false"`?

CSS has the :disabled pseudo-class, since elements that are children of <fieldset disabled> act as if they had the attribute set themselves.

That would change the _focusableElementsString to look more like input:not(:disabled).

Similarly, contenteditable="false" actually means something, because contenteditable isn't a boolean variable, just confusingly similar to one. When set to false, it's not focusable. That would probably change its selector to [contenteditable]:not([contenteditable="true" i]).

document.contains issue in IE11

Hi there

I came across an issue when testing in IE11 - the document.contains was throwing an error. (Line 115)

I've changed it to
if (!document.body.contains(startNode))

to resolve the isssue

Inerting element in shadow DOM throws error

If you try to inert an element in a shadow root, inert.js throws an error when trying to get the root.activeElement and pass it to compareDocumentPosition.

let div = document.createElement('div');
let shadow = div.attachShadow({mode: 'open'});
shadow.innerHTML = '<button>btn 1</button><button>btn 2</button>'

shadow.querySelector('button').inert = true 

/*
inert.js:73 Uncaught TypeError: Failed to execute 'compareDocumentPosition' on 'Node': parameter 1 is not of type 'Node'.
    at contains (inert.js:73)
    at InertRoot._makeSubtreeUnfocusable (inert.js:250)
    at new InertRoot (inert.js:162)
    at InertManager.setInert (inert.js:717)
    at HTMLButtonElement.set$$1 [as inert] (inert.js:1020)
    at <anonymous>:1:38
*/

Error: Mismatched anonymous define() module:

Hi,
I still use requirejs: https://requirejs.org/ . Salesforce uses your module in their LiveChat. Your built version uses an anonymous define. RequireJS doesn't like that (see also https://requirejs.org/docs/errors.html ). LiveChat breaks our pages due to the anonymous define. This could quite easily be fixed, for example like this:

(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? factory() :
  typeof define === 'function' && define.amd ? define(['inert'], factory) : // give it a name
  (factory());
}(this, (function () { 'use strict';

Cheers Vincent

An in-range update of rollup is breaking the build 🚨

Version 0.51.7 of rollup was just published.

Branch Build failing 🚨
Dependency rollup
Current Version 0.51.6
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

rollup is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • continuous-integration/travis-ci/push The Travis CI build could not complete due to an error Details

Commits

The new version differs by 6 commits.

  • 172d72a Fix code style
  • 923b6fd 0.51.7
  • 03c6b90 Update changelog
  • 1d05530 Merge pull request #1724 from nathancahill/fix-sequence-this-context
  • a9b842c add function test for sequence context
  • 6b1c0bc maintain this context when sequence is callable

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Add minified build to dist

Hi,

Could you please rebuild with the minified version of inert in the dist? Some packages have dependencies on the minified build that I cannot change.

Thanks!

In IE10, readyState is sometimes incorrect and inert tries to observe a document.body which is null

In IE10, readyState is sometimes incorrect and inert tries to observe a document.body which is null. Possibly this is similar to what is being described in #75.

Basically, from what I can tell, https://github.com/WICG/inert/blob/master/src/inert.js#L481 is flagged incorrectly, and as a result, https://github.com/WICG/inert/blob/master/src/inert.js#L589 crashes due to document.body being null. I see in the comment here: https://github.com/WICG/inert/blob/master/src/inert.js#L588 that this is not always needed (and is actually not in my team's particular case). Is there a way we could expose a way to programmatically disable the document.body functionality?

Any reports of IE11 dying unexpectedly?

Hey Folks!

Love the library and a11ycasts, quick question, "Any reports of IE11 dying unexpectedly?" And by dying, I mean not being able to hit breakpoints or logs at all, just dies. Was hoping to submit a PR, but nothing is really standing out as an issue. Any insider clues?

High-level, basically working through accessible modal dialogs as taught by Rob in this episode of a11ycasts:
https://www.youtube.com/watch?v=JS68faEUduk

The inert library worked out really well, just this one scenario where it's failing for IE11 customers while closing one type of modal we have. The library works fine for another type of modal we have, so I'm aware maybe we have some CSS property (or combination of properties) or maybe some HTML layout/attribute that's causing a critical failure in the IE11 rendering engine/MutationObserver event handler.

We're not "dead in the water" or anything because I was able to replicate the core library function. The replication is good enough atm, but would ideally like to continue using inert because of its collective polish. Any thoughts on where I should focus in the inert library? Any IE11 reports that might jog a memory or two?

Accessibility lawsuits are heating up and on the radar for major web-based products (including ours), so Thanks for advancing accessibility efforts and Keep up the good work!

Option to use with data-attribute

We are using inert in a recent project. It works well and we want to continue to use it.
Our product must deliver valid HTML without errors. It is checked with the W3 validator.

However, the validator doesn't allow to use the inert attribute anywhere, because it isn't part of the spec. As to why was explained in this issue of the HTML spec.

Would it be possible to have the polyfill not only work with [inert]-attribute, but also with a [data-inert]-attribute? That way we can make use of this future-proof feature (and might do a little switch somewhere in the future), but also deliver fully valid HTML.

Define property if undefined

Object.defineProperty(Element.prototype, 'inert', {

I get an error on the inert import, particularly with running Jest tests on my Vue components. We have a couple components that use inert but don't want it always imported if the component(s) aren't being used. Could the definition be wrapped in a conditional to only apply if !Element.prototype.inert?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.