JSFiddle - React, Tailwind, and code Playground

HTML

<div>
  <label for="propertyName">property name</label>
  <input type="text" id="propertyName" />
  <br />
  <label for="attributeName">Attribute name</label>
  <input type="text" id="attributeName" />
  <br />
  <label for="attributeValue">Attribute value</label>
  <input type="text" id="attributeValue" />
  <br />
  <br />
  <button id="define">define attribute</button>
  <div id="list">

  </div>
</div>

JavaScript

var testObject = {
  a: 1,
  b: 2,
  c: 3
};

listAttributes();

document.getElementById('define').addEventListener('click', defineClick);

function defineClick() {
  var propName = document.getElementById('propertyName').value;
  var attrName = document.getElementById('attributeName').value;
  var value = document.getElementById('attributeValue').value;

  setPropertyAttribute(testObject, propName, attrName, value);
  listAttributes();
}

function listAttributes() {
  var list = '<ul>';
  for (var prop in testObject) {

    list += '<li><strong>' + prop + ' : ' + testObject[prop] + '</strong><br/>';

    list += '<h3>attributes</h3><dl>';
    var attributes = getPropertyAttributes(testObject, prop);
    for (var attr in attributes) {
      list += '<dt>' + attr + '</dt><dd>' + attributes[attr] + '</dd>';
    }

    list += '</dl></li>';
  }

  document.getElementById('list').innerHTML = list;
}

function setPropertyAttribute(obj, propertyName, attributeName, attributeValue) {
  var descriptor = getCustomPropertyDescriptor(obj, propertyName);

  descriptor.get.$custom[attributeName] = attributeValue;
}

function getPropertyAttributes(obj, propertyName) {
  var descriptor = getCustomPropertyDescriptor(obj, propertyName);

  return descriptor.get.$custom;
}

function getPropertyAttribute(obj, propertyName, attributeName) {
  return getPropertyAttributes(obj, propertyName)[attributeName];
}

function getCustomPropertyDescriptor(obj, prop) {
  var actualDescriptor = Object.getOwnPropertyDescriptor(obj, prop);
  if (actualDescriptor && actualDescriptor.get && actualDescriptor.get.$custom) {
    return actualDescriptor;
  }

  var value = obj[prop];
  var descriptor = {
    get: function() {
      return value;
    },
    set: function(newValue) {
      value = newValue;
    }
  }
  descriptor.get.$custom = {};

  Object.defineProperty(obj, prop, descriptor);
  return Object.getOwnPropertyDescriptor(obj, prop);
}