I'd like some comments and any suggestions that you have for where to go next with this.
I've been working on developing a JavaScript library that allows for dynamic forms by simply adding some extra HTML tags and attributes to your form. It's brand new, so it doesn't have a lot of features, but it's based on the idea that you shouldn't need to write a bunch of JavaScript and have to deal with bugs and stuff just to get your form to have multiple pages or to add new fields when you click a button... stuff like that.
All you have to do to make it work is include jQuery and this JavaScript in the page after all the form HTML.
...
<script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js'></script>
<script type='text/javascript' src='edomform.js'></script>
</body>
I've got the current JavaScript in a Fiddle with some example HTML and CSS, and some basic documentation/guide material in a Google doc that you can comment on if you like. Any comments and suggestions are welcome.
You're also welcome to use this for whatever you want as-is or with any modifications you or anyone comes up with.
//Configuration variables
var config = jQuery("edfconfig");
function getConfigBoolean(attr) {
    if (config != null)
    return jQuery(config).attr(attr) != undefined;
}
function getConfigValue(attr) {
    if (config != null)
    return jQuery(config).attr(attr);
}
var noasterisks         = getConfigBoolean("noasterisks");
var addafter            = getConfigBoolean("addafter");
var doactions           = getConfigBoolean("doactions");
var noappend            = getConfigBoolean("noappend");
var requiredmessage     = getConfigValue("requiredmessage");
var requiredmessageid   = getConfigValue("requiredmessageid");
//eDomForm variables
var attrs = jQuery("edfvars")[0];
var variables = {};
if (attrs != null)
for (i=0;i<attrs.attributes.length;i++) {
    variables[attrs.attributes[i].nodeName] = attrs.attributes[i].nodeValue;
}
//Function because jQuery doesn't have a selector for the name attribute
function getByName(n) {
    return document.getElementsByName(n);
}
//required fields have the class required_field
var required = jQuery(".required_field");
//message div to display global form messages
var message = jQuery("#message");
//reference to the entire form itself
var form = jQuery("#form");
//form data
jQuery(form).data("required_empty",required.length);
//Add next and back buttons
jQuery(".form_page").each(function(i){
    jQuery(this).prepend('<button type="button" class="back">Back</button> <button type="button" class="next">Next</button>');
});
//Next and Back buttons
var pages = jQuery(".form_page");
var backButtons = jQuery(".back");
var nextButtons = jQuery(".next");
for (i=0;i<pages.length;i++) {
    if (i != pages.length-1) {
        nextButtons[i].onclick = function() {
            jQuery(this).closest("div").fadeOut();
            jQuery(this).closest("div").nextAll(":not(.disabled):first").fadeIn();
        };
    } else {
        jQuery(nextButtons[i]).remove();
    }
    if (i != 0) {
        backButtons[i].onclick = function(i) {
            jQuery(this).closest("div").fadeOut();
            jQuery(this).closest("div").prevAll(":not(.disabled):first").fadeIn();
        };
    } else {
        jQuery(backButtons[i]).remove();
    }
}
//Aliases
function getByAlias(a) {
    return jQuery("[alias="+a+"]");
}
function hasClass(element, cls) {
    return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;
}
var aliases = jQuery(".alias");
for (i=0;i<aliases.length;i++) {
    var alias = jQuery(aliases[i]).attr("alias");
    var original = jQuery("."+alias);
    for (j=0;j<original.length;j++) {
        if (hasClass(original[j],"required_field")) {
            jQuery(aliases[i]).addClass("required_field");
        }
        original[j].onchange = aliasChange.bind(null,original[j],aliases[i]);
        aliases[i].onchange = aliasChange.bind(null,aliases[i],original[j]);
    }
}
function aliasChange(o,a) {
    a.value = o.value;
    a.onblur();
}
var radioGroupCounter = 1;
jQuery(document).ready(function() {
    //Prevent form submission if required fields have not been filled in
    if (form[0] != null)
    form[0].onsubmit = function() {
        var required_fields = document.getElementsByClassName("required_field");
        for (i=0;i<required_fields.length;i++) {
            if (required_fields[i].value == "") {
                jQuery("#"+requiredmessageid).html(requiredmessage);
                return false;
            }
        }
        jQuery("#"+requiredmessageid).html("");
        return true;
    };
    //Hidden pages
    function handleHiddenPages() {
        jQuery(".revealer").each(function(i){
            var page = jQuery(this).attr("page");
            jQuery(this).click(function(){
                if (jQuery(this).is(":checked")) {
                    jQuery("."+page).removeClass("disabled");
                } else {
                    jQuery("."+page).addClass("disabled");
                }
            });
        });
    }
    handleHiddenPages();
    //Switchers
    function handleSwitchers() {
        jQuery(".switcher").each(function(x){
            var connections = jQuery(this).attr("connections");
            connections = jQuery.parseJSON(connections);
            var connectedSections = {};
            for (var key in connections) {
                //if something like a-b
                if (connections[key].indexOf("-") > -1) {
                    var nums = connections[key].split("-");
                    var resultNums = [];
                    for (i=0;i<nums.length;i++) {
                        nums[i] = parseInt(nums[i]);
                    }
                    for (i=nums[0];i<=nums[nums.length-1];i++) {
                        resultNums.push(i+"");
                        connectedSections[i] = key;
                    }
                } else {
                    if (connections.hasOwnProperty(key))
                    connectedSections[connections[key]] = key;
                }
            }
            jQuery(this).change(function(){
                for (var key in connectedSections) {
                    jQuery("."+connectedSections[key]).hide();
                }
                jQuery("."+connectedSections[jQuery(this).val()]).show();
            });
        });
    }
    handleSwitchers();
    //Displayers/Hiders
    function handleDisplayers() {
        jQuery(".displayer").each(function(x){
            var connected = jQuery(this).attr("display");
            var special = "";
            var connecteds = [];
            if (connected.indexOf(" ") > -1) {
                connecteds = connected.split(" ");
                var special = connecteds[0];
                connected = connecteds[1];
            }
            var name = jQuery(this).attr("name");
            var group = getByName(name);
            jQuery(group).each(function() {
                jQuery(this).on("click",function() {
                var button = this;
                    if (jQuery(this).attr("display") != null) {
                        if (special == "") {
                            jQuery("."+connected).each(function() {
                                jQuery(this).show();
                            });
                        }
                        else if (special == "next") {
                            jQuery("."+connected).each(function() {
                                if (button.compareDocumentPosition(this) == 4) {
                                    jQuery(this).show();
                                    return false;
                                }
                            });
                        }
                        else if (special == "prev") {
                            jQuery(jQuery("."+connected).get().reverse()).each(function(i) {
                            if (button.compareDocumentPosition(this) == 2) {
                                jQuery(this).show();
                                return false;
                            }
                        });
                        }
                    }else {
                        if (special == "") {
                            jQuery("."+connected).each(function() {
                                jQuery(this).hide();
                            });
                        }
                        else if (special == "next")
                        jQuery("."+connected).each(function() {
                            if (button.compareDocumentPosition(this) == 4) {
                                jQuery(this).hide();
                                return false;
                            }
                        });
                        else if (special == "prev")
                        jQuery(jQuery("."+connected).get().reverse()).each(function(i) {
                            if (button.compareDocumentPosition(this) == 2) {
                                jQuery(this).hide();
                                return false;
                            }
                        });
                    }
                });
            });
        });
    }
    handleDisplayers();
    //findNext function from stackoverflow
    /**
     * Find the next element matching a certain selector. Differs from next() in
     *  that it searches outside the current element's parent.
     *  
     * @param selector The selector to search for
     * @param steps (optional) The number of steps to search, the default is 1
     * @param scope (optional) The scope to search in, the default is document wide 
     */
    $.fn.findNext = function(selector, steps, scope)
    {
        // Steps given? Then parse to int 
        if (steps)
        {
            steps = Math.floor(steps);
        }
        else if (steps === 0)
        {
            // Stupid case :)
            return this;
        }
        else
        {
            // Else, try the easy way
            var next = this.next(selector);
            if (next.length)
                return next;
            // Easy way failed, try the hard way :)
            steps = 1;
        }
        // Set scope to document or user-defined
        scope = (scope) ? $(scope) : $(document);
        // Find kids that match selector: used as exclusion filter
        var kids = this.find(selector);
        // Find in parent(s)
        hay = $(this);
        while(hay[0] != scope[0])
        {
            // Move up one level
            hay = hay.parent();     
            // Select all kids of parent
            //  - excluding kids of current element (next != inside),
            //  - add current element (will be added in document order)
            var rs = hay.find(selector).not(kids).add($(this));
            // Move the desired number of steps
            var id = rs.index(this) + steps;
            // Result found? then return
            if (id > -1 && id < rs.length)
                return $(rs[id]);
        }
        // Return empty result
        return $([]);
    }
    //Adding New Sections
    function handleAdds() {
        jQuery(".add").each(function(x){
            var add = jQuery(this).attr("add");
            if (add.indexOf(" ") > -1) {
                add = add.split(" ");
            }
            var to = jQuery(this).attr("to");
            var radiogroup = jQuery(this).attr("radiogroup");
            if (radiogroup != null)
            radiogroup = radiogroup.split(" ");
            var cpy = jQuery("<div />").append(jQuery("."+add).clone()).html();
            if (to == null) {
                jQuery(this).click(function() {
                    var text = cpy;
                    var counter = radioGroupCounter++;
                    if (radiogroup != null)
                    for (i=0;i<radiogroup.length;i++) {
                        var re = new RegExp(radiogroup[i]+"\\[\\d\\]","g");
                        text = text.replace(re,radiogroup[i]+"["+(counter)+"]");
                    }
                    if (addafter)
                    jQuery(this).after(text);
                    else
                    jQuery(this).before(text);
                    handleHiddenPages();
                    handleDisplayers();
                    handleSwitchers();
                });
            } else {
                if (to.indexOf(" ") > -1) {
                    to = to.split(" ");
                }
                jQuery(this).click(function() {
                    var text = cpy;
                    var counter = radioGroupCounter++;
                    if (radiogroup != null)
                    for (i=0;i<radiogroup.length;i++) {
                        var re = new RegExp(radiogroup[i]+"\\[\\d\\]","g");
                        text = text.replace(re,radiogroup[i]+"["+(counter)+"]");
                        console.log(text);
                    }
                    jQuery("#"+to).append(text);
                    handleHiddenPages();
                    handleDisplayers();
                    handleSwitchers();
                });
            }
        });
    }
    handleAdds();
    //Action tags
    function handleAll() {
        handleHiddenPages();
        handleDisplayers();
        handleSwitchers();
        handleAdds();
    }
});
required = jQuery(".required_field");
//Loop through required fields, adding the onblur event
//so that whenever the user deselects a required field,
//if it is blank the asterisk will turn red.
for (i=0;i<required.length;i++) {
    jQuery(required[i]).after("<span>*</span>");
    jQuery(required[i]).data("empty",true);
    required[i].onblur = function() {
        if (this.value == "") {
            jQuery(this).next().css("color","#f00");
        } else {
            jQuery(this).next().css("color","#000");
        }
    };
}
