JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js"></script>
<div data-bind="with:pctInput">
<label>Value</label>
<input class="activeInput" data-bind='textInput: base, event:{blur:toggle}, visible:editing, hasFocus:editing' />
<input data-bind='textInput: formatted, event:{focus:toggle}, visible:!editing()' readonly='true' />
</div>
<div data-bind="with:commaInput">
<label>Another Value</label>
<input class="activeInput" data-bind='textInput: base, event:{blur:toggle}, visible:editing, hasFocus:editing' />
<input data-bind='textInput: formatted, event:{focus:toggle}, visible:!editing()' readonly='true' />
CSS
.activeInput { background-color: #fee; }
JavaScript
function editableFormatted(formatFn) {
var self = {
base: ko.observable(''),
editing: ko.observable(false)
};
self.formatted = ko.computed(function () {
return formatFn(self.base());
});
self.toggle = function() {
self.editing(!self.editing());
};
return self;
}
function formatPct(num) {
return num === '' ? '' : num + '%';
}
function formatCommas(num) {
var formatted = num.replace(/\B(?=(\d{3})+$)/g, ',');
console.debug("Formatted:", formatted);
return formatted;
}
var viewModel = {
pctInput: editableFormatted(formatPct),
commaInput: editableFormatted(formatCommas)
};
ko.applyBindings(viewModel);