JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://github.com/downloads/SteveSanderson/knockout/knockout-1.3.0beta.js"></script>
<script src="https://raw.github.com/SteveSanderson/knockout.mapping/master/build/output/knockout.mapping-latest.js"></script>
<div>
    <button data-bind="click: function() { undo(); }">Undo</button>
    <input data-bind="value: firstName" />
    <input data-bind="value: lastName" />
    <textarea data-bind="value: text"></textarea>
</div>

CSS

textarea{
  padding : 10px;
}

JavaScript

(function() {
    
    //current state would probably come from the server, hard coded here for example
    var currentState = JSON.stringify({
        firstName: 'Paul',
        lastName: 'Tyng',
        text: 'Text' 
    })
       , undoStack = [] //this represents all the previous states of the data in JSON format
        , performingUndo = false //flag indicating in the middle of an undo, to skip pushing to undoStack when resetting properties
        , viewModel = ko.mapping.fromJSON(currentState); //enriching of state with observables
        
    
    //this creates a dependent observable subscribed to all observables 
    //in the view (toJS is just a shorthand to traverse all the properties)
    //the dependent observable is then subscribed to for pushing state history
    ko.dependentObservable(function() {
        ko.toJS(viewModel); //subscribe to all properties    
    }, viewModel).subscribe(function() {
        if(!performingUndo) {
        undoStack.push(currentState);
        currentState = ko.mapping.toJSON(viewModel);
    }
    });
        
    //pops state history from undoStack, if its the first entry, just retrieve it
        window.undo = function() {
            performingUndo = true;
            if(undoStack.length > 1)
            {
                currentState = undoStack.pop();
                ko.mapping.fromJSON(currentState, {}, viewModel);
            }
            else {
                currentState = undoStack[0];
                ko.mapping.fromJSON(undoStack[0], {}, viewModel);
            }
            performingUndo = false;
    };
    
    ko.applyBindings(viewModel);
})();