diff --git a/elements.module b/elements.module
index ed66a30..7d025cc 100644
--- a/elements.module
+++ b/elements.module
@@ -51,11 +51,44 @@ function elements_element_info() {
     '#theme' => 'rangefield',
     '#theme_wrappers' => array('form_element'),
   );
+  $types['horizontal_tabs'] = array(
+    '#theme_wrappers' => array('horizontal_tabs'),
+    '#default_tab' => '',
+    '#process' => array('form_process_horizontal_tabs'),
+    '#attached' => array(
+      'library' => array(
+        array('elements', 'horizontal-tabs'),
+      ),
+    ),
+  );
 
   return $types;
 }
 
 /**
+ * Implements hook_library().
+ */
+function elements_library() {
+
+  $path = drupal_get_path('module', 'elements');
+
+  // Horizontal Tabs.
+  $libraries['horizontal-tabs'] = array(
+    'title' => 'Horizontal Tabs',
+    'website' => 'http://drupal.org/node/323112',
+    'version' => '1.0',
+    'js' => array(
+      $path . '/horizontal-tabs/horizontal-tabs.js' => array(),
+    ),
+    'css' => array(
+      $path . '/horizontal-tabs/horizontal-tabs.css' => array(),
+    ),
+  );
+
+  return $libraries;
+}
+
+/**
  * Implements hook_element_info_alter().
  */
 function elements_element_info_alter(&$types) {
@@ -105,6 +138,11 @@ function elements_theme() {
       'render element' => 'element',
       'file' => 'elements.theme.inc',
     ),
+    'horizontal_tabs' => array(
+      'arguments' => array('element' => NULL),
+      'render element' => 'element',
+      'file' => 'elements.theme.inc',
+    ),
   );
 }
 
@@ -154,3 +192,40 @@ function form_process_placeholder($element) {
   }
   return $element;
 }
+
+/**
+ * Creates a group formatted as horizontal tabs.
+ *
+ * @param $element
+ *   An associative array containing the properties and children of the
+ *   fieldset.
+ * @param $form_state
+ *   The $form_state array for the form this horizontal tab widget belongs to.
+ * @return
+ *   The processed element.
+ */
+function form_process_horizontal_tabs($element, &$form_state) {
+  // Inject a new fieldset as child, so that form_process_fieldset() processes
+  // this fieldset like any other fieldset.
+  $element['group'] = array(
+    '#type' => 'fieldset',
+    '#theme_wrappers' => array(),
+    '#parents' => $element['#parents'],
+  );
+
+  // The JavaScript stores the currently selected tab in this hidden
+  // field so that the active tab can be restored the next time the
+  // form is rendered, e.g. on preview pages or when form validation
+  // fails.
+  $name = implode('__', $element['#parents']);
+  if (isset($form_state['values'][$name . '__active_tab'])) {
+    $element['#default_tab'] = $form_state['values'][$name . '__active_tab'];
+  }
+  $element[$name . '__active_tab'] = array(
+    '#type' => 'hidden',
+    '#default_value' => $element['#default_tab'],
+    '#attributes' => array('class' => array('horizontal-tabs-active-tab')),
+  );
+
+  return $element;
+}
diff --git a/elements.theme.inc b/elements.theme.inc
index 12b1706..b049a36 100644
--- a/elements.theme.inc
+++ b/elements.theme.inc
@@ -142,3 +142,22 @@ function theme_rangefield($variables) {
 
   return $output;
 }
+
+/**
+ * Returns HTML for an element's children fieldsets as horizontal tabs.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - element: An associative array containing the properties and children of the
+ *     fieldset. Properties used: #children.
+ *
+ * @ingroup themeable
+ */
+function theme_horizontal_tabs($variables) {
+  $element = $variables['element'];
+
+  $output = '<h2 class="element-invisible">' . (!empty($element['#title']) ? $element['#title'] : t('Horizontal Tabs')) . '</h2>';
+  $output .= '<div class="horizontal-tabs-panes">' . $element['#children'] . '</div>';
+
+  return $output;
+}
diff --git a/horizontal-tabs/horizontal-tabs.css b/horizontal-tabs/horizontal-tabs.css
new file mode 100644
index 0000000..60d9e08
--- /dev/null
+++ b/horizontal-tabs/horizontal-tabs.css
@@ -0,0 +1,92 @@
+@CHARSET "UTF-8";
+
+div.horizontal-tabs {
+  margin: 0 0 1em 0; /* LTR */
+  padding: 0;
+  border: 1px solid #ccc;
+  position: relative; /* IE6/7 */
+}
+
+.horizontal-tabs ul.horizontal-tabs-list {
+  display: inline-block;
+  margin: 0;
+  border: 0;
+  padding: 0px;
+  position: relative; /* IE6 */
+  list-style: none;
+  list-style-image: none; /* IE6 */
+  background-color: #dedede;
+  border-right: 1px solid #dedede;
+  width: 100%;
+  height: auto;
+  clear: both;
+}
+
+.horizontal-tabs fieldset.horizontal-tabs-pane {
+  padding: 0 1em;
+  border: 0;
+}
+
+.horizontal-tabs-pane>legend {
+  display: none;
+}
+
+/* Layout of each tab */
+.horizontal-tabs ul.horizontal-tabs-list li {
+  background: #eee;
+  border-right: 1px solid #ccc;
+  padding: 1px;
+  padding-top: 0; 
+  margin: 0;
+  min-width: 5em; /* IE7 */
+  float: left;
+}
+.horizontal-tabs ul.horizontal-tabs-list li.selected {
+  background-color: #fff;
+  padding: 0 0 1px 0;
+}
+.horizontal-tabs ul.horizontal-tabs-list li a {
+  display: block;
+  text-decoration: none;
+  padding: 0.5em 0.6em;
+}
+.horizontal-tabs ul.horizontal-tabs-list li a:hover {
+  outline: none;
+  background-color: #ededdd;
+}
+.horizontal-tabs ul.horizontal-tabs-list li:hover,
+.horizontal-tabs ul.horizontal-tabs-list li:focus {
+  background-color: #ddd;
+}
+.horizontal-tabs ul.horizontal-tabs-list li a:focus strong,
+.horizontal-tabs ul.horizontal-tabs-list li a:active strong,
+.horizontal-tabs ul.horizontal-tabs-list li a:hover strong {
+  text-decoration: none;
+  outline: none;
+}
+.horizontal-tabs ul.horizontal-tabs-list li a,
+.horizontal-tabs ul.horizontal-tabs-list li.selected a {
+  display: block;
+  text-decoration: none;
+  padding: 0.5em 0.6em 0.3em 0.6em;
+  position:relative;
+  top: 0px;  
+}
+.horizontal-tabs ul.horizontal-tabs-list .selected strong {
+  color: #000;
+}
+.horizontal-tabs ul.horizontal-tabs-list .summary {
+  display: block;
+}
+.horizontal-tabs ul.horizontal-tabs ul.horizontal-tabs-list .summary {
+  line-height: normal;
+  margin-bottom: 0;
+}
+
+/**
+ * tab content 
+ */
+div.field-group-htabs-wrapper .field-group-format-wrapper { 
+  clear: both;
+  padding: 0 0 0.6em;
+}
\ No newline at end of file
diff --git a/horizontal-tabs/horizontal-tabs.js b/horizontal-tabs/horizontal-tabs.js
new file mode 100644
index 0000000..cf2ab2a
--- /dev/null
+++ b/horizontal-tabs/horizontal-tabs.js
@@ -0,0 +1,204 @@
+(function ($) {
+
+/**
+ * This script transforms a set of fieldsets into a stack of horizontal
+ * tabs. Another tab pane can be selected by clicking on the respective
+ * tab.
+ *
+ * Each tab may have a summary which can be updated by another
+ * script. For that to work, each fieldset has an associated
+ * 'horizontalTabCallback' (with jQuery.data() attached to the fieldset),
+ * which is called every time the user performs an update to a form
+ * element inside the tab pane.
+ */
+Drupal.behaviors.horizontalTabs = {
+  attach: function (context) {
+    $('.horizontal-tabs-panes', context).once('horizontal-tabs', function () {
+      var focusID = $(':hidden.horizontal-tabs-active-tab', this).val();
+      var tab_focus;
+
+      // Check if there are some fieldsets that can be converted to horizontal-tabs
+      var $fieldsets = $('> fieldset', this);
+      if ($fieldsets.length == 0) {
+        return;
+      }
+
+      // Create the tab column.
+      var tab_list = $('<ul class="horizontal-tabs-list"></ul>');
+      $(this).wrap('<div class="horizontal-tabs clearfix"></div>').before(tab_list);
+
+      // Transform each fieldset into a tab.
+      $fieldsets.each(function () {
+        var horizontal_tab = new Drupal.horizontalTab({
+          title: $('> legend', this).text(),
+          fieldset: $(this)
+        });
+        tab_list.append(horizontal_tab.item);
+        $(this)
+          .removeClass('collapsible collapsed')
+          .addClass('horizontal-tabs-pane')
+          .data('horizontalTab', horizontal_tab);
+        if (this.id == focusID) {
+          tab_focus = $(this);
+        }
+      });
+
+      $('> li:first', tab_list).addClass('first');
+      $('> li:last', tab_list).addClass('last');
+
+      if (!tab_focus) {
+        // If the current URL has a fragment and one of the tabs contains an
+        // element that matches the URL fragment, activate that tab.
+        if (window.location.hash && $(window.location.hash, this).length) {
+          tab_focus = $(window.location.hash, this).closest('.horizontal-tabs-pane');
+        }
+        else {
+          tab_focus = $('> .horizontal-tabs-pane:first', this);
+        }
+      }
+      if (tab_focus.length) {
+        tab_focus.data('horizontalTab').focus();
+      }
+    });
+  }
+};
+
+/**
+ * The horizontal tab object represents a single tab within a tab group.
+ *
+ * @param settings
+ *   An object with the following keys:
+ *   - title: The name of the tab.
+ *   - fieldset: The jQuery object of the fieldset that is the tab pane.
+ */
+Drupal.horizontalTab = function (settings) {
+  var self = this;
+  $.extend(this, settings, Drupal.theme('horizontalTab', settings));
+
+  this.link.click(function () {
+    self.focus();
+    return false;
+  });
+
+  // Keyboard events added:
+  // Pressing the Enter key will open the tab pane.
+  this.link.keydown(function(event) {
+    if (event.keyCode == 13) {
+      self.focus();
+      // Set focus on the first input field of the visible fieldset/tab pane.
+      $("fieldset.horizontal-tabs-pane :input:visible:enabled:first").focus();
+      return false;
+    }
+  });
+
+  // Pressing the Enter key lets you leave the tab again.
+  this.fieldset.keydown(function(event) {
+    // Enter key should not trigger inside <textarea> to allow for multi-line entries.
+    if (event.keyCode == 13 && event.target.nodeName != "TEXTAREA") {
+      // Set focus on the selected tab button again.
+      $(".horizontal-tab-button.selected a").focus();
+      return false;
+    }
+  });
+
+  this.fieldset
+    .bind('summaryUpdated', function () {
+      self.updateSummary();
+    })
+    .trigger('summaryUpdated');
+};
+
+Drupal.horizontalTab.prototype = {
+  /**
+   * Displays the tab's content pane.
+   */
+  focus: function () {
+    this.fieldset
+      .show()
+      .siblings('fieldset.horizontal-tabs-pane')
+        .each(function () {
+          var tab = $(this).data('horizontalTab');
+          tab.fieldset.hide();
+          tab.item.removeClass('selected');
+        })
+        .end()
+      .siblings(':hidden.horizontal-tabs-active-tab')
+        .val(this.fieldset.attr('id'));
+    this.item.addClass('selected');
+    // Mark the active tab for screen readers.
+    $('#active-horizontal-tab').remove();
+    this.link.append('<span id="active-horizontal-tab" class="element-invisible">' + Drupal.t('(active tab)') + '</span>');
+  },
+
+  /**
+   * Updates the tab's summary.
+   */
+  updateSummary: function () {
+    this.summary.html(this.fieldset.drupalGetSummary());
+  },
+
+  /**
+   * Shows a horizontal tab pane.
+   */
+  tabShow: function () {
+    // Display the tab.
+    this.item.show();
+    // Update .first marker for items. We need recurse from parent to retain the
+    // actual DOM element order as jQuery implements sortOrder, but not as public
+    // method.
+    this.item.parent().children('.horizontal-tab-button').removeClass('first')
+      .filter(':visible:first').addClass('first');
+    // Display the fieldset.
+    this.fieldset.removeClass('horizontal-tab-hidden').show();
+    // Focus this tab.
+    this.focus();
+    return this;
+  },
+
+  /**
+   * Hides a horizontal tab pane.
+   */
+  tabHide: function () {
+    // Hide this tab.
+    this.item.hide();
+    // Update .first marker for items. We need recurse from parent to retain the
+    // actual DOM element order as jQuery implements sortOrder, but not as public
+    // method.
+    this.item.parent().children('.horizontal-tab-button').removeClass('first')
+      .filter(':visible:first').addClass('first');
+    // Hide the fieldset.
+    this.fieldset.addClass('horizontal-tab-hidden').hide();
+    // Focus the first visible tab (if there is one).
+    var $firstTab = this.fieldset.siblings('.horizontal-tabs-pane:not(.horizontal-tab-hidden):first');
+    if ($firstTab.length) {
+      $firstTab.data('horizontalTab').focus();
+    }
+    return this;
+  }
+};
+
+/**
+ * Theme function for a horizontal tab.
+ *
+ * @param settings
+ *   An object with the following keys:
+ *   - title: The name of the tab.
+ * @return
+ *   This function has to return an object with at least these keys:
+ *   - item: The root tab jQuery element
+ *   - link: The anchor tag that acts as the clickable area of the tab
+ *       (jQuery version)
+ *   - summary: The jQuery element that contains the tab summary
+ */
+Drupal.theme.prototype.horizontalTab = function (settings) {
+  var tab = {};
+  tab.item = $('<li class="horizontal-tab-button" tabindex="-1"></li>')
+    .append(tab.link = $('<a href="#"></a>')
+      .append(tab.title = $('<strong></strong>').text(settings.title))
+      .append(tab.summary = $('<span class="summary"></span>')
+    )
+  );
+  return tab;
+};
+
+})(jQuery);
diff --git a/tests/elements.test b/tests/elements.test
new file mode 100644
index 0000000..649a82e
--- /dev/null
+++ b/tests/elements.test
@@ -0,0 +1,34 @@
+<?php
+/**
+ * @file
+ * Tests elements.
+ */
+
+
+/**
+ * Testing elements
+ */
+class ElementsTest extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => t('Elements'),
+      'description' => t('Tests the declared elements.'),
+      'group' => t('Elements'),
+    );
+  }
+
+  function setUp() {
+    parent::setUp('content');
+  }
+
+  /**
+   * Tests if horizontal tabs are displayed properly.
+   */
+  function testHorizontalTabs() {
+    $account = $this->drupalCreateUser(array('administer content types', 'access content', 'create page content'));
+    $this->drupalLogin($account);
+
+  }
+
+}
\ No newline at end of file
