Skip to content

Instantly share code, notes, and snippets.

@CodeMyUI
Created November 16, 2017 01:44
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save CodeMyUI/c27d44ead857d1cb93d1e8be85f4123a to your computer and use it in GitHub Desktop.
Save CodeMyUI/c27d44ead857d1cb93d1e8be85f4123a to your computer and use it in GitHub Desktop.
React right-click context menu
<div id="root"></div>

React right-click context menu

Just an experiment. Not suitable for production. Right-click context menu React component.

A Pen by devHamsters on CodePen.

License.

class ContextMenu extends React.Component {
state = {
visible: false,
};
componentDidMount() {
document.addEventListener('contextmenu', this._handleContextMenu);
document.addEventListener('click', this._handleClick);
document.addEventListener('scroll', this._handleScroll);
};
componentWillUnmount() {
document.removeEventListener('contextmenu', this._handleContextMenu);
document.removeEventListener('click', this._handleClick);
document.removeEventListener('scroll', this._handleScroll);
}
_handleContextMenu = (event) => {
event.preventDefault();
this.setState({ visible: true });
const clickX = event.clientX;
const clickY = event.clientY;
const screenW = window.innerWidth;
const screenH = window.innerHeight;
const rootW = this.root.offsetWidth;
const rootH = this.root.offsetHeight;
const right = (screenW - clickX) > rootW;
const left = !right;
const top = (screenH - clickY) > rootH;
const bottom = !top;
if (right) {
this.root.style.left = `${clickX + 5}px`;
}
if (left) {
this.root.style.left = `${clickX - rootW - 5}px`;
}
if (top) {
this.root.style.top = `${clickY + 5}px`;
}
if (bottom) {
this.root.style.top = `${clickY - rootH - 5}px`;
}
};
_handleClick = (event) => {
const { visible } = this.state;
const wasOutside = !(event.target.contains === this.root);
if (wasOutside && visible) this.setState({ visible: false, });
};
_handleScroll = () => {
const { visible } = this.state;
if (visible) this.setState({ visible: false, });
};
render() {
const { visible } = this.state;
return(visible || null) &&
<div ref={ref => {this.root = ref}} className="contextMenu">
<div className="contextMenu--option">Share this</div>
<div className="contextMenu--option">New window</div>
<div className="contextMenu--option">Visit official site</div>
<div className="contextMenu--option contextMenu--option__disabled">View full version</div>
<div className="contextMenu--option">Settings</div>
<div className="contextMenu--separator" />
<div className="contextMenu--option">About this app</div>
</div>
};
}
ReactDOM.render(<ContextMenu />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react-dom.min.js"></script>
#root {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: linear-gradient(75deg, #00E39F, #00C4E1);
&::before {
content: 'Right click anywhere on the screen!';
font-family: sans-serif;
font-size: 12px;
color: white;
}
}
.contextMenu {
position: fixed;
background: white;
box-shadow: 0px 2px 10px #999999;
&--option {
padding: 6px 50px 5px 10px;
min-width: 160px;
cursor: default;
font-size: 12px;
&:hover {
background: linear-gradient(to top, #555, #333);
color: white;
}
&:active {
color: #e9e9e9;
background: linear-gradient(to top, #555, #444);
}
&__disabled {
color: #999999;
pointer-events: none;
}
}
&--separator {
width: 100%;
height: 1px;
background: #CCCCCC;
margin: 0 0 0 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment