skip to Main Content

When an input element is disabled, it won’t be handled by any event.

<input disabled />

How to achieve that for any element (e.g. a span element)?

I’ve tried using pointer-events: "none" but it only prevents click events. Other event such as onKeyDown can still be called.

Here is an example :

import * as React from "react";

export default function UnstyledSwitches() {
  return (
    <div>
      <span tabIndex={0} onKeyDown={() => console.log("clicked")}>
        test
      </span>
    </div>
  );
}

https://codesandbox.io/s/base-cra-typescript-forked-43708i?file=/src/App.tsx

Focus on the span with tab and then click spacebar. The function that is supplied to onKeyDown props will be called. I want the function to not be called.

2

Answers


  1. One solution can be to add the disabled attribute to the element and then use javascript to limit eventListeners to not-disabled elements.

    For example:

    In html:

     <span disabled>Disabled</span>
     <span>Open to events</span>
    

    In js:

    document.querySelector('span:not([disabled=""])').addEventListener("event", handler);
    

    But, if elements are being disabled/enabled dynamically, you’d need to add eventListeners after each change in element’s state.

    Login or Signup to reply.
  2. pointerEvents and tabIndex

    The question asks how to prevent keyboard input on a span. However, the code included in the question assigns a value to the element’s tabIndex. Setting the tabIndex (or contentEditable) attribute allows the element to receive focus along with keyboard events.

    Removing the tabIndex from the span prevents focus and keyboard events, but not mouse events. To prevent both keyboard and mouse events, set pointerEvents to "none". The tabIndex setting doesn’t appear to make any difference with a span, but might with an input.

    OP notes that pointerEvents "none" did not work and yet in the snippet it does. The reason is unclear, but perhaps it due to different testing methods.

    React Snippet

    The snippet contains a few span elements with different configurations to try.

    const {useState} = React;
    
    ReactDOM.render(
        
          <div>
          
          <span  
            onClick={(e) => log(e)}
            onKeyDown={(e) => log(e)}
            onFocus={(e) => log(e)}
          >
            tabIndex none
          </span>
          
          <span tabIndex={0} 
            onClick={(e) => log(e)}
            onKeyDown={(e) => log(e)}
            onFocus={(e) => log(e)}
          >
            tabIndex 0
          </span>
          
          <span 
            style={{pointerEvents: "none"}}
            onClick={(e) => log(e)}
            onKeyDown={(e) => log(e)}
            onFocus={(e) => log(e)}
          >
            pointer-events none
          </span>
    
        </div>
      
    , document.getElementById("root"));
    
    
    function log(e) { console.log(e.type) }
    .pointer-events-none {
      pointer-events: none;
    }
    
    span {
      margin: 0.5rem;
      padding: 1rem;
      border: thin dotted blue;
      border-radius: 0.5rem;
    }
    
    span:focus {
      background-color: lightyellow;
    }
    
    body {
      font-family: sans-serif;
      margin: 1rem;
    }
    .as-console-wrapper { max-height: 100px !important; }
    <p>
    click on a span and then type some text using keyboard
    </p>
    
    <div id="root"></div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search