JSFiddle - React, Tailwind, and code Playground

HTML

<button value="tab1View" class="tabButton current" id="tab1Tab">Tab 1</button>
<button value="tab2View" class="tabButton" id="tab2Tab">Tab 2</button>
<hr>
<div class="tabDiv" id="tab1View">This is tab 1
    <br />There is a form on this tab. This form must be validated and submitted successfully before switching to tab 2.</div>
<div class="hidden tabDiv" id="tab2View">This is tab 2
    <br/>The contents of this tab depend on the form in tab 1 having been successfully ssubmitted to the server.</div>

CSS

#tabs {
    margin:0px;
    padding:0px;
    padding-bottom:-1px;
    width:100%;
    border-bottom:1px solid #C9C9C9;
    margin-bottom:5px;
    position:relative;
    z-index:1;
}
.tabButton {
    margin:0px;
    margin-right:3px;
    padding:5px;
    border:1px solid #C9C9C9;
    background-color:#EAEAEA;
    background: linear-gradient(to top, #FFFFFF, #DBDBDB);
    position:relative;
    top:1px;
    z-index: 2;
    border-top-right-radius: 5px;
    border-top-left-radius: 5px;
}
button.tabButton:not(.current):hover {
    background-color:#DFDFDF;
    border-left-color: #878787;
    border-top-color: #878787;
    border-right-color: #878787;
}
.tabButton.current {
    background-color:white;
    border-bottom:1px solid white;
}
.tabBadge {
    width:12px;
    height:12px;
    border:2px solid white;
    padding:2px;
    background-color:red;
    color: white;
    font-size: .75em;
    position:relative;
    left:-12px;
    top:-10px;
    text-align: center;
    border-radius: 12px;
    z-index:3;
}
.hidden {
    display:none;
}

JavaScript

$(document).ready(function () {
    $('.tabButton').click(changeTab);

    //bind a "before show" function to tab 2
    $('#tab2Tab').bind('beforeShow', tab2BeforeShow);
});

function changeTab() {
    var jqButton = $(this);
    if (jqButton.hasClass("current")) //don't do anything if switching to the current tab
    return;

    //run the "before show" function, if any.
    var eventParams = {
        promise: null
    };
    jqButton.trigger('beforeShow', eventParams);
    function doShowTab(showTab) {
        if (!showTab) //if no before show function, then showTab is null, not false
        return; //if false, then don't show the tab.

        $(".tabDiv").hide();

        //run any "after hide" scripts bound to the current tab
        $('.tabButton.current').trigger('afterHide');

        var requestedDiv = jqButton.val(); //the "value" of the tab button is the ID of the tab content div
        $("#" + requestedDiv).show(); //may show nothing, if no div exists for the current tab.
        $(".tabButton").removeClass("current"); //remove the current class from all tab buttons, so it will only be applied to the new current tab button.
        jqButton.addClass("current");
    }
    if (eventParams.promise) eventParams.promise.then(doShowTab);
    else doShowTab(true);
}

function tab2BeforeShow(e, eventParams) {
    // run some AJAX function here. In my case, this is a ajaxForm object submit.
    // $('#SomeajaxFormObject').submit();

    // The result of this AJAX function determines if this function should set 
    // the 'show' data of the tab to false, thereby preventing tab 2 from being shown
    // See line 14.
    // PROBLEM: this function returns immediately after calling the ajax function,
    // and completing the rest of this function, but before the ajax success/failure callbacks.
    // that would determine if the 'show' data should be set to false.
    // Therefore the tab is ALWAYS shown, even if the result of the above submit is negative.
   ...