1

In my ReactJS project, I'm using <Dialog> (http://www.material-ui.com/#/components/dialog), and when I open up the <Dialog> and press command + a on Mac, it highlights the whole page rather than just the content in the <Dialog>.

How can I highlight just the content inside <Dialog> while the <Dialog> is open by pressing command + a on Mac?

Thank you in advance and will accept/upvote the answer.

Jo Ko
  • 7,225
  • 15
  • 62
  • 120

1 Answers1

2

Yes, this can be done. You'll need to listen for Command-A (or Ctrl-A on Windows) on window.document in componentDidMount() and perform the text selection programmatically. For cleanup, you un-listen in componentWillUnmount().

Working example here: http://www.webpackbin.com/41BuFVuBz

import React from 'react';
import { Dialog } from 'material-ui';

class HelloWorld extends React.Component {
  constructor(props) {
    super(props);
    // In ES6 classes, class methods like handleKeyDown aren't automatically bound to "this"
    this.handleKeyDown = this.handleKeyDown.bind(this);
  }

  handleKeyDown(e) {
    // If the A key is pressed while CTRL or COMMAND are also being pressed
    if (e.key === 'a' && (e.ctrlKey || e.metaKey)) {
      // Don't perform the default action, which would select everything on page
      e.preventDefault();

      const win = window;
      const doc = win.document;
      // this.dialogBody is the div's DOM element captured in the ref={}
      const element = this.dialogBody;

      if (doc.body.createTextRange) {      // check if this is Internet Explorer
        // Select all text in "element", the IE way
        var range = doc.body.createTextRange();
        range.moveToElementText(element);
        range.select();
      } else if (win.getSelection) {      // other browsers...
        // Select all text in "element", the standard way
        var selection = win.getSelection();
        var range = doc.createRange();
        range.selectNodeContents(element);
        selection.removeAllRanges();
        selection.addRange(range);
      }     
    }
  }

  componentDidMount() {
    // Element has been rendered, start capturing keyboard activity
    window.document.addEventListener('keydown', this.handleKeyDown);
  }

  componnetWillUnmount() {
    // Element is no longer been rendered, stop listening
    window.document.removeEventListener('keydown', this.handleKeyDown);
  }

  render() {
    return (
      <div>
        <p>
          Some text I don't want selected.
        </p>
        <p>
          More text I don't want selected.
        </p>
        <Dialog open>
          // Capture a reference to the div's DOM element inside ref={...} as this.dialogBody
          <div ref={(ref) => (this.dialogBody = ref)}>
            <h1>Hello World!</h1>
            <p>Nice day, isn't it?</p>
          </div>
        </Dialog>
      </div>
    );
  }
}

export default HelloWorld;

The code that actually performs the selection of text confined to a DOM element can be seen in slight variations in other answers on SO:

Select all DIV text with single mouse click

selecting all text within a div on a single left click with javascript

Select all or highlight all Text in an Element

...the only additional 'trick' is knowing where to put DOM manipulation code like this within the React component lifecycle (primarily componentDidMount, usually with the help of a ref, and sometimes cleanup is necessary in componentWillUnmount)

Community
  • 1
  • 1
Jeff McCloud
  • 5,777
  • 1
  • 19
  • 21
  • Thank you! It worked beautifully but I'm trying to learn as well. Before I accept the answer and upvote, do you mind briefly commenting as to how each line is working? Thank you! – Jo Ko Jan 12 '17 at 01:43
  • Sure! I just added comments. Hope that helps! – Jeff McCloud Jan 12 '17 at 17:42