diff --git a/source/Ox.UI/js/Form/Ox.FormPanel.js b/source/Ox.UI/js/Form/Ox.FormPanel.js
new file mode 100644
index 00000000..ea4bab30
--- /dev/null
+++ b/source/Ox.UI/js/Form/Ox.FormPanel.js
@@ -0,0 +1,157 @@
+'use strict';
+
+Ox.FormPanel = function(options, self) {
+
+ self = self || {};
+ var that = Ox.Element({}, self)
+ .defaults({
+ form: []
+ })
+ .options(options || {});
+
+ self.sections = self.options.form.map(function(section) {
+ return section.title;
+ });
+ self.section = 0;
+ self.sectionTitle = self.sections[self.section].title;
+ self.$list = Ox.TextList({
+ columns: [
+ {
+ format: function(value) {
+ return $('')
+ .attr({
+ src: Ox.UI.getImageURL('symbolCheck')
+ })
+ .css({
+ width: '10px',
+ height: '10px',
+ margin: '2px 2px 2px 0',
+ opacity: value ? 1 : 0.1
+ })
+ },
+ id: 'valid',
+ title: 'Valid',
+ visible: true,
+ width: 16
+ },
+ {
+ format: function(value) {
+ return (getSectionIndexByTitle(value) + 1) + '. ' + value;
+ },
+ id: 'title',
+ title: 'Title',
+ unique: true,
+ visible: true,
+ width: 240
+ }
+ ],
+ items: function(data, callback) {
+ setTimeout(function() {
+ callback({
+ data: {
+ items: Ox.isEmpty(data)
+ ? self.sections.length
+ : self.options.form.map(function(section) {
+ return {title: section.title, valid: section.valid};
+ })
+ }
+ });
+ }, 250);
+ },
+ max: 1,
+ min: 1,
+ selected: [self.sections[0].id],
+ sort: [{key: 'id', operator: '+'}],
+ width: 256
+ }).bindEvent({
+ select: function(data) {
+ self.$sections[self.section].hide();
+ Ox.forEach(self.options.form, function(section, i) {
+ if (section.title == data.ids[0]) {
+ self.section = i;
+ return false;
+ }
+ });
+ self.$sections[self.section].show();
+ }
+ });
+
+ self.$section = $('