JSFiddle - React, Tailwind, and code Playground
HTML
<!-- using contenteditable -->
<h2>Contenteditable</h2>
<div class="stepperContainer">
<button>-</button>
<span class="ce-container">
<span class="ce-input" contenteditable="true" role="textbox" aria-label="text size multiplier"></span>
<span class="ce-unit">X</span>
</span>
<button>+</button>
</div>
<strong>Value: </strong><span class="ce-output"></span>
<ul>
<li><strong>JAWS:</strong><span>text size multiplier edit type and text</span></li>
<li><strong>Narrator:</strong><span>text size multiplier editting "value"</span></li>
<li><strong>NVDA:</strong><span>text size multiplier edit "value"</span></li>
<li><strong>VoiceOver:</strong><span>"value", Insertion at beginngin of text. text size multiplier, edit text</span></li>
</ul>
<!-- Centred input -->
<h2>Centred on Input</h2>
<div class="stepperContainer">
<button>-</button>
<span class="in-container">
<input class="inputElm" type="text" size="1" aria-label="text size multiplier">
<span class="in-unit">X</span>
</span>
<button>+</button>
</div>
<strong>Value: </strong><span class="in-output"></span>
<ul>
<li><strong>JAWS:</strong><span>text size multiplier edit type and text</span></li>
<li><strong>Narrator:</strong><span>text size multiplier editting "value"</span></li>
<li><strong>NVDA:</strong><span>text size multiplier edit has auto completet selected "value"</span></li>
<li><strong>VoiceOver:</strong><span>"value", contents selected, text size multiplier, edit text</span></li>
</ul>
<!-- Centred input -->
<h2>Unit to right of Input</h2>
<div class="stepperContainer">
<button>-</button>
<span class="ur-container">
<input class="ur-input" type="text" aria-label="text size multiplier">
<span class="ur-unit">X</span>
</span>
<button>+</button>
</div>
<strong>Value: </strong><span class="ur-output"></span>
<ul>
<li><strong>JAWS:</strong><span>text size multiplier edit type and...
CSS
/* General styling for steppers */
.stepperContainer {
display: flex;
}
.stepperContainer button {
border: 2px solid #000000;
border-radius: 0.4rem;
background-color: #ffffff;
height: 2.4375rem;
width: 2.4375rem;
margin: 0 1rem;
}
/* Contenteditable */
.ce-container {
width: 5rem;
background-color: #ffffff;
border: 1px solid #000000;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.2rem;
}
.ce-input {
min-width: 1rem;
white-space: nowrap;
overflow: hidden;
text-align: right;
}
.ce-unit {
padding-left: 0.2rem;
}
/* Centred Input */
.in-container {
width: 5rem;
background-color: #ffffff;
border: 1px solid #000000;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.2rem;
}
.inputElm {
border: none;
background-color: transparent;
text-align: right;
padding: 0 0.1rem;
font-size: 1.2rem;
}
/* Unit to the right of Input */
.ur-container {
width: 5rem;
background-color: #ffffff;
border: 1px solid #000000;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.2rem;
}
.ur-input {
width: 3.5rem;
border: none;
text-align: right;
font-size: 1.2rem;
}
.ur-unit {
padding-left: 0.2rem;
}
JavaScript
// Contenteditable
// issue with cut and paste containing new line characters
var ceInput = $(".ce-input");
var ceWrite = function () {
$(".ce-output").text(ceInput.text());
};
ceInput.on("blur", ceWrite);
ceInput.on("keypress", function (event) {
// capture "enter"
if (event.which === 13) {
event.preventDefault();
ceWrite();
}
});
// Centered Input
// have to manually resize textfield
var centredInput = $(".inputElm");
centredInput.on("input", function (event) {
var maxSize = 5;
var inChars = centredInput.val().length;
var curSize = +centredInput.attr("size");
if (inChars !== curSize) {
centredInput.attr("size", Math.min(inChars, maxSize) || 1);
}
});
centredInput.on("change", function () {
$(".in-output").text(centredInput.val());
});
// Unit to the left
var urInput = $(".ur-input");
urInput.on("change", function () {
$(".ur-output").text(urInput.val());
});