JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://cdn.jsdelivr.net/npm/sceditor@2/minified/sceditor.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sceditor@2/minified/formats/bbcode.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sceditor@2/minified/formats/xhtml.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sceditor@2/minified/plugins/autosave.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sceditor@2/minified/plugins/autoyoutube.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sceditor@2/minified/plugins/dragdrop.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sceditor@2/minified/plugins/format.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sceditor@2/minified/plugins/plaintext.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sceditor@2/minified/plugins/undo.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sceditor@2/minified/themes/default.min.css">
<script src="https://cdn.jsdelivr.net/npm/sceditor@2/minified/icons/monocons.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sceditor@2/minified/icons/material.js"></script>
<textarea id="test"></textarea>

CSS

body {
  font-family: sans-serif
}
#test {
  width: 100%;
  height: 20em;
}

JavaScript

sceditor.command.set('indent', {
  state: function (parent, firstBlock) {
    // Only works with lists, for now
    var	range, startParent, endParent;

    if (sceditor.dom.is(firstBlock, 'li')) {
      return 0;
    }

    if (sceditor.dom.is(firstBlock, 'ul,ol,menu')) {
      // if the whole list is selected, then this must be
      // invalidated because the browser will place a
      // <blockquote> there
      range = this.getRangeHelper().selectedRange();

      startParent = range.startContainer.parentNode;
      endParent   = range.endContainer.parentNode;

      // TODO: could use nodeType for this?
      // Maybe just check the firstBlock contains both the start
      //and end containers

      // Select the tag, not the textNode
      // (that's why the parentNode)
      if (startParent !==
          startParent.parentNode.firstElementChild ||
          // work around a bug in FF
          (sceditor.dom.is(endParent, 'li') && endParent !==
           endParent.parentNode.lastElementChild)) {
        return 0;
      }
    }

    return -1;
  },
  exec: function () {
    var editor = this,
        block = editor.getRangeHelper().getFirstBlockParent();

    editor.focus();

    // An indent system is quite complicated as there are loads
    // of complications and issues around how to indent text
    // As default, let's just stay with indenting the lists,
    // at least, for now.
    if (dom.closest(block, 'ul,ol,menu')) {
      editor.execCommand('indent');
    }
  },
});

sceditor.command.set('outdent', {
  state: function (parents, firstBlock) {
    return sceditor.dom.closest(firstBlock, 'ul,ol,menu') ? 0 : -1;
  },
  exec: function () {
    var	block = this.getRangeHelper().getFirstBlockParent();
    if (sceditor.dom.closest(block, 'ul,ol,menu')) {
      this.execCommand('outdent');
    }
  }
});

var textarea = document.getElementById('test');
sceditor.create(textarea, {
	icons: 'monocons',
  format: 'bbcode',
  emoticonsRoot:...