JSFiddle - React, Tailwind, and code Playground

by dswitzer

HTML

<h1>
  Message Box Control Mockup
</h1>
<p>
  Toolbars are not shown unless the textarea has focus or there has been some text entered. This will prevent any screen shifting upon focus with elements being shown/hidden.
</p>
<p>
  This demo does show auto-growing the text area based on the size of the content, so there are never any scrollbars. While this would cause DOM shifting, it will only happen once text is entered that is larger than the textarea.
</p>
<div class="textbox-control">
  <div class="textbox-control-header">
    Top Toolbar
  </div>
  <textarea class="textbox-form-control" oninput="this.parentNode.classList[this.value.length ? 'add' : 'remove']('textbox-control-has-content'); this.parentNode.dataset.textContent = this.value;"></textarea>
  <div class="textbox-control-footer">
    Bottom Toolbar
  </div>
</div>

CSS

* {
  box-sizing: border-box;  
}

.textbox-control {
  position: relative;
  display: grid;
  border: 1px solid #ccc;
  max-width: 800px;
}

/* for autosize textarea */
.textbox-control::after {
  /* Note the weird space! Needed to preventy jumpy behavior */
  content: attr(data-text-content) " ";

  /* This is how textarea text behaves */
  white-space: pre-wrap;

  /* Hidden from view, clicks, and screen readers */
  visibility: hidden;
}

.textbox-control:focus-within {
  outline: 1px solid blue;
}

.textbox-control:focus-within .textbox-control-header,
.textbox-control:focus-within .textbox-control-footer,
.textbox-control-has-content .textbox-control-header,
.textbox-control-has-content .textbox-control-footer {
  visibility: visible;
}

.textbox-control-header,
.textbox-control-footer {
  position: absolute;
  left: 0;
  right: 0;
  background-color: rgba(204, 204, 204, 0.25);
  padding: 0.25em 1em;
  height: 1.7em;
  z-index: 2;
  visibility: hidden;
}

.textbox-control-header {
  top: 0;
}

.textbox-control-footer {
  bottom: 0;
}

.textbox-control::after,
.textbox-form-control {
  padding: 2.5em 1em 2.75em;
  width: 100%;
  border: 0;
  z-index: 1;
  outline: 0;
  /*
  resize: vertical;
  */

  /* for autosizing */
  /* Place on top of each other */
  grid-area: 1 / 1 / 2 / 2;
  font: 1em monospace;
  line-height: 1.25em;
}

 /* for autosizing */
.textbox-form-control {
  resize: none;
  /* Firefox shows scrollbar on growth, you can hide like this. */
  overflow: hidden;  
}