JSFiddle - React, Tailwind, and code Playground

HTML

<link rel="stylesheet" href="http://draftrr.com/static/css/bootstrap.css">
<script src="http://draftrr.com/static/js/bootstrap.min.components.js"></script>
<input type="button" id="attach" value="Attach Contextual Menu">
<input type="button" id="destroy" value="Destroy Contextual Menu">
<div id="box">Right Click Me</div>

CSS

body{
    padding:20px;
}
#box{
    background:#eee;
    border:1px solid #ddd;
    padding:50px;
    color:#999;
    font-family:arial;
    text-align:center;
    margin-top:20px;
}
.dropdown-context:before {
  position: absolute;
  top: -7px;
  left: 9px;
  display: inline-block;
  border-right: 7px solid transparent;
  border-bottom: 7px solid #ccc;
  border-left: 7px solid transparent;
  border-bottom-color: rgba(0, 0, 0, 0.2);
  content: '';
}
.dropdown-context:after {
  position: absolute;
  top: -6px;
  left: 10px;
  display: inline-block;
  border-right: 6px solid transparent;
  border-bottom: 6px solid #ffffff;
  border-left: 6px solid transparent;
  content: '';
}

JavaScript

var context = context || (function() {

    var initialized = false;

    function init() {
        $(document).on('click', 'html', function() {
            $('.dropdown-context').fadeOut(100);
        });
    }

    function addContext(selector, id, data) {
        if (!initialized) {
            init();
            initialized = true;
        }

        $menu = $('<ul class="dropdown-menu dropdown-context" id="dropdown-' + id + '"></ul>');

        for (var i in data) {
            if (typeof data[i].divider == 'boolean' && data[i].divider) {
                $menu.append('<li class="divider"></li>');
            } else {
                $menu.append('<li><a tabindex="-1" href="' + data[i].href + '">' + data[i].text + '</a></li>');
            }
        }
        $('body').append($menu);

        $(document).on('contextmenu', selector, function(e) {
            e.preventDefault();
            $('#dropdown-' + id).css({
                top: e.pageY + 10,
                left: e.pageX - 13
            }).fadeIn(100);
        });
    }

    function destroyContext(selector) {
        $(document).off('contextmenu', selector);
    }

    return {
        attach: addContext,
        destroy: destroyContext
    };
})();

$(document).on('click', '#attach', function() {
    context.attach('#box', 'box', [
        { href: '#', text: 'Action 1' },
        { href: '#', text: 'Action 2' },
        { href: '#', text: 'Action 3' },
        { divider: true },
        { href: '#', text: 'Action 4' }
    ]);
});

$(document).on('click', '#destroy', function() {
    context.destroy('#box');
});