diff --git a/css/webform-admin.css b/css/webform-admin.css
index 0476638..8076574 100644
--- a/css/webform-admin.css
+++ b/css/webform-admin.css
@@ -117,3 +117,57 @@ tr.webform-add-form .tabledrag-changed {
 #webform-components tr.webform-add-form {
   background-color: inherit;
 }
+
+/* Conditionals */
+.webform-conditional {
+  display: block;
+  position: relative;
+  padding-left: 1em;
+  padding-right: 8em;
+  max-width: 500px;
+}
+
+.webform-conditional-if {
+  position: absolute;
+  left: -.5em;
+  margin-top: .2em;
+}
+
+.webform-conditional-condition {
+  display: inline;
+}
+
+.webform-conditional-operations {
+  position: absolute;
+  right: 0;
+  margin-top: .2em;
+}
+
+.webform-conditional-operations input {
+  margin: 0 2px;
+}
+
+#webform-conditionals-table input.progress-disabled,
+.webform-conditional-operations input.progress-disabled {
+  float: none;
+}
+
+#webform-conditionals-table .ahah-progress-throbber {
+  float: none;
+  display: inline;
+}
+
+#webform-conditionals-table .ahah-progress-throbber .throbber {
+  float: none;
+  display: inline;
+  padding-right: 12px;
+}
+
+.webform-conditional-andor {
+  display: inline;
+}
+
+.webform-conditional-andor .form-item {
+  margin: 0;
+  padding: 0;
+}
diff --git a/includes/webform.components.inc b/includes/webform.components.inc
index d1de2f3..e58c4dc 100644
--- a/includes/webform.components.inc
+++ b/includes/webform.components.inc
@@ -496,69 +496,6 @@ function webform_component_edit_form(&$form_state, $node, $component, $clone = F
     '#weight' => 4,
   );
 
-  // Add conditional fields.
-  $conditional_components = array();
-  $counter = 0;
-  $last_pagebreak_slice = 0;
-  foreach ($node->webform['components'] as $cid => $test_component) {
-    // Only components before the pagebreak can be considered.
-    if ($test_component['type'] == 'pagebreak') {
-      $last_pagebreak_slice = $counter;
-    }
-    if (isset($component['cid']) && $cid == $component['cid']) {
-      break;
-    }
-    if (webform_component_feature($test_component['type'], 'conditional')) {
-      $conditional_components[$cid] = $test_component;
-    }
-    $counter++;
-  }
-  if ($component['type'] != 'pagebreak') {
-    $fieldset_description = t('Create a rule to control whether or not to skip this page.');
-  }
-  else {
-    $fieldset_description = t('Create a rule to control whether or not to show this form element.');
-  }
-  $conditional_components = array_slice($conditional_components, 0, $last_pagebreak_slice, TRUE);
-  $form['conditional'] = array(
-    '#weight' => 10,
-    '#type' => 'fieldset',
-    '#title' => t('Conditional rules'),
-    '#collapsible' => TRUE,
-    '#collapsed' => TRUE,
-    '#description' => t('Create a rule to control whether or not to show this form element.'),
-    '#tree' => FALSE,
-  );
-  $form['conditional']['extra'] = array(
-    '#tree' => TRUE,
-  );
-  $form['conditional']['extra']['conditional_component'] = array(
-    '#type' => 'select',
-    '#title' => t('Component'),
-    '#options' => webform_component_list($node, $conditional_components, FALSE, TRUE),
-    '#description' => t('Select another component to decide whether to show or hide this component. You can only select components occurring before the most recent pagebreak.'),
-    '#default_value' => $component['extra']['conditional_component'],
-  );
-  $form['conditional']['extra']['conditional_operator'] = array(
-    '#type' => 'select',
-    '#title' => t('Operator'),
-    '#options' => array(
-      '=' => t('Is one of'),
-      '!=' => t('Is not one of')
-    ),
-    '#description' => t('Determines whether the list below is inclusive or exclusive.'),
-    '#default_value' => $component['extra']['conditional_operator'],
-  );
-  $form['conditional']['extra']['conditional_values'] = array(
-    '#type' => 'textarea',
-    '#title' => t('Values'),
-    '#description' => t('List values, one per line, that will trigger this action. If you leave this blank, this component will always display.'),
-    '#default_value' => $component['extra']['conditional_values'],
-  );
-  if (empty($conditional_components)) {
-    $form['conditional']['#access'] = FALSE;
-  }
-
   // Add the fields specific to this component type:
   $additional_form_elements = (array) webform_component_invoke($component['type'], 'edit', $component);
   if (empty($additional_form_elements)) {
@@ -861,6 +798,19 @@ function webform_component_feature($type, $feature) {
 }
 
 /**
+ * Get a component property from the component definition.
+ *
+ * @see hook_webform_component_info()
+ */
+function webform_component_property($type, $property) {
+  $components = webform_components();
+  $defaults = array(
+    'conditional_type' => 'string',
+  );
+  return isset($components[$type][$property]) ? $components[$type][$property] : $defaults[$property];
+}
+
+/**
  * Create a list of components suitable for a select list.
  *
  * @param $node
diff --git a/includes/webform.pages.inc b/includes/webform.pages.inc
index 99bc8a8..30c65d8 100644
--- a/includes/webform.pages.inc
+++ b/includes/webform.pages.inc
@@ -400,3 +400,60 @@ function theme_webform_advanced_redirection_form($form) {
   $form['redirect']['url']['#title'] = $form['redirect']['url']['#title'] . ': ' . drupal_render($form['redirect_url']);
   return drupal_render($form);
 }
+
+/**
+ * AJAX Callback to provide Drupal 6 functionality similar to AJAX in Drupal 7.
+ *
+ * This function takes the incoming $_POST request, processes the form to build
+ * $form and $form_state, then calls the #ahah[callback] property on the clicked
+ * button, making it so that #ahah can be used the same way as #ajax would in
+ * Drupal 7.
+ *
+ * This function is based on the AHAH example, slighly modified to call the
+ * original clicked button callback.
+ *
+ * @see http://api.drupal.org/api/examples/ahah_example%21ahah_example.module/function/ahah_example_callback_helper/6
+ * @see http://api.drupal.org/api/drupal/developer%21topics%21forms_api_reference.html/7#ajax_callback
+ */
+function webform_ajax_callback() {
+  // We don't have any way of including files for AJAX requests through
+  // $form_state like we do in Drupal 7 e.g. form_load_include(), so we just
+  // manually include files that contain Webform form callbacks.
+  module_load_include('inc', 'webform', 'includes/webform.conditionals');
+
+  $form_state = array(
+    'storage' => NULL,
+    'submitted' => FALSE,
+  );
+  $form_build_id = $_POST['form_build_id'];
+  $form = form_get_cache($form_build_id, $form_state);
+  $args = $form['#parameters'];
+  $form_id = array_shift($args);
+  $form_state['post'] = $form['#post'] = $_POST;
+  // Enable the submit/validate handlers to determine whether AHAH-submittted.
+  $form_state['ahah_submission'] = TRUE;
+  $form['#programmed'] = $form['#redirect'] = FALSE;
+  drupal_process_form($form_id, $form, $form_state);
+  $form = drupal_rebuild_form($form_id, $form_state, $args, $form_build_id);
+
+  $callback = $form_state['clicked_button']['#ahah']['callback'];
+  if (function_exists($callback)) {
+    $output = $callback($form, $form_state);
+
+    // Add a manual fix to extend the list of AHAH element settings on the page.
+    $data = drupal_add_js();
+    $embed_prefix = "\n<!--//--><![CDATA[//><!--\n";
+    $embed_suffix = "\n//--><!]]>\n";
+    $settings = call_user_func_array('array_merge_recursive', $data['setting']);
+    $output .= '<script type="text/javascript">' . $embed_prefix . 'jQuery.extend(Drupal.settings.ahah, ' . drupal_to_js($settings['ahah']) . ');' . $embed_suffix . '</script>';
+
+    $output = theme('status_messages') . $output;
+
+    drupal_json(array('status' => TRUE, 'data' => $output));
+  }
+  else {
+    drupal_set_message(t('An AJAX callback was either not found or undefined.'), 'error');
+    $output = theme('status_messages');
+    drupal_json(array('status' => TRUE, 'data' => $output));
+  }
+}
diff --git a/js/webform-admin.js b/js/webform-admin.js
index b54783f..59a5b2b 100644
--- a/js/webform-admin.js
+++ b/js/webform-admin.js
@@ -14,6 +14,8 @@ Drupal.behaviors.webformAdmin = function(context) {
   Drupal.webform.selectCheckboxesLink(context);
   // Enhance the normal tableselect.js file to support indentations.
   Drupal.webform.tableSelectIndentation(context);
+  // Enhance the normal tableselect.js file to support indentations.
+  Drupal.webform.conditionalAdmin(context);
 }
 
 Drupal.webform = Drupal.webform || {};
@@ -114,3 +116,131 @@ Drupal.webform.tableSelectIndentation = function(context) {
   });
 }
 
+/**
+ * Attach behaviors for Webform conditional administration.
+ */
+Drupal.webform.conditionalAdmin = function(context) {
+  $('.webform-conditional:not(.webform-conditional-processed)').each(function() {
+    $(this).addClass('webform-conditional-processed');
+
+    // Rather than binding to click, we have to use mousedown to work with
+    // the AJAX handling, which disables the button and prevents "click" events.
+    // This handler needs a delay to let the form submit before we remove the
+    // table row.
+    $(this).find('.webform-conditional-rule-remove').mousedown(function() {
+      var button = this;
+      window.setTimeout(Drupal.webform.conditionalRemove.apply(button), 10);
+    });
+
+    $(this).find('.webform-conditional-source select').each(function() {
+      $(this).change(Drupal.webform.conditionalSourceChange).triggerHandler('change');
+    });
+
+    $(this).find('.webform-conditional-operator select').each(function() {
+      $(this).change(Drupal.webform.conditionalOperatorChange).triggerHandler('change');
+    });
+
+    $(this).find('.webform-conditional-andor select').each(function() {
+      $(this).change(Drupal.webform.conditionalAndOrChange).triggerHandler('change');
+    });
+  });
+}
+
+/**
+ * Event callback for the remove button next to an individual rule.
+ */
+Drupal.webform.conditionalRemove = function() {
+  // See if there are any remaining rules in this element.
+  var ruleCount = $(this).parents('.webform-conditional:first').find('.webform-conditional-rule-remove').length;
+  if (ruleCount <= 1) {
+    var tableRow = $(this).parents('tr:first');
+    var table = $('#webform-conditionals-table');
+    if (tableRow.length && table.length) {
+      table.find(tableRow[0]).remove();
+      Drupal.webform.restripeTable(table[0]);
+    }
+  }
+}
+
+/**
+ * Event callback to update the list of operators after a source change.
+ */
+Drupal.webform.conditionalSourceChange = function() {
+  var source = $(this).val();
+  var dataType = Drupal.settings.webform.conditionalValues.sources[source]['data_type'];
+  var $operator = $(this).parents('.webform-conditional-rule:first').find('.webform-conditional-operator select');
+
+  // Store a the original list of all operators for all data types in the select
+  // list DOM element.
+  if (!$operator[0]['webformConditionalOriginal']) {
+    $operator[0]['webformConditionalOriginal'] = $operator[0].innerHTML;
+  }
+
+  // Reference the original list to create a new list matching the data type.
+  var $originalList = $($operator[0]['webformConditionalOriginal']);
+  var $newList = $originalList.filter('optgroup[label=' + dataType + ']');
+  $operator[0].innerHTML = $newList[0].innerHTML;
+
+  // Fire the change event handler on the list to update the value field.
+  $operator.triggerHandler('change');
+}
+
+/**
+ * Event callback to update the list of operators after a source change.
+ */
+Drupal.webform.conditionalOperatorChange = function() {
+  var source = $(this).parents('.webform-conditional-rule:first').find('.webform-conditional-source select').val();
+  var dataType = Drupal.settings.webform.conditionalValues.sources[source]['data_type'];
+  var operator = $(this).val();
+  var $value = $(this).parents('.webform-conditional-rule:first').find('.webform-conditional-value');
+  var value = $value.find('input, select, textarea').val();
+  var name = $value.find('input, select, textarea').attr('name');
+
+
+  // Given the dataType and operator, we can determine the form key.
+  var formKey = Drupal.settings.webform.conditionalValues.operators[dataType][operator]['form'];
+
+  // Save the default field as printed on the original page.
+  if (!$value[0]['webformConditionalOriginal']) {
+    $value[0]['webformConditionalOriginal'] = $value[0].innerHTML;
+  }
+
+  if (formKey === 'default') {
+    $value[0].innerHTML = $value[0]['webformConditionalOriginal'];
+  }
+  else {
+    // If there is a per-source form for this operator (e.g. option lists), use
+    // the specialized value form.
+    if (typeof Drupal.settings.webform.conditionalValues.forms[formKey] == 'object') {
+      $value[0].innerHTML = Drupal.settings.webform.conditionalValues.forms[formKey][source];
+    }
+    // Otherwise all the sources use a generic field (e.g. a text field).
+    else {
+      $value[0].innerHTML = Drupal.settings.webform.conditionalValues.forms[formKey];
+    }
+  }
+
+  $value.find('input, select, textarea').filter(':first').val(value).attr('name', name);
+}
+
+/**
+ * Event callback to make sure all group and/or operators match.
+ */
+Drupal.webform.conditionalAndOrChange = function() {
+  $(this).parents('.webform-conditional:first').find('.webform-conditional-andor select').val(this.value);
+}
+
+/**
+ * Given a table's DOM element, restripe the odd/even classes.
+ */
+Drupal.webform.restripeTable = function(table) {
+  // :even and :odd are reversed because jQuery counts from 0 and
+  // we count from 1, so we're out of sync.
+  // Match immediate children of the parent element to allow nesting.
+  $('> tbody > tr.draggable, > tr.draggable', table)
+    .filter(':odd').filter('.odd')
+      .removeClass('odd').addClass('even')
+    .end().end()
+    .filter(':even').filter('.even')
+      .removeClass('even').addClass('odd');
+};
diff --git a/webform.install b/webform.install
index 2ab991b..31e7333 100644
--- a/webform.install
+++ b/webform.install
@@ -183,6 +183,107 @@ function webform_schema() {
     'primary key' => array('nid', 'cid'),
   );
 
+  $schema['webform_conditional'] = array(
+    'description' => 'Holds information about conditional logic.',
+    'fields' => array(
+      'nid' => array(
+        'description' => 'The node identifier of a webform.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'rgid' => array(
+        'description' => 'The rule group identifier for this group of rules.',
+        'type' => 'int',
+        'size' => 'small',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'andor' => array(
+        'description' => 'Whether to AND or OR the actions in this group. All actions within the same crid should have the same andor value.',
+        'type' => 'varchar',
+        'length' => 128,
+      ),
+      'action' => array(
+        'description' => 'The action to be performed on the target. Typically "show" or "hide" for targets of type "component", and "send" for targets of type "email".',
+        'type' => 'varchar',
+        'length' => 128,
+      ),
+      'target_type' => array(
+        'description' => 'The type of target to be affected. Either "component" or "email". Indicates what type of ID the "target" column contains.',
+        'type' => 'varchar',
+        'length' => 128,
+      ),
+      'target' => array(
+        'description' => 'The ID of the target to be affected. Typically a component ID.',
+        'type' => 'varchar',
+        'length' => 128,
+      ),
+      'weight' => array(
+        'description' => 'Determines the position of this conditional compared to others.',
+        'type' => 'int',
+        'size' => 'small',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+    'primary key' => array('nid', 'rgid'),
+  );
+
+  $schema['webform_conditional_rules'] = array(
+    'description' => 'Holds information about conditional logic.',
+    'fields' => array(
+      'nid' => array(
+        'description' => 'The node identifier of a webform.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'rgid' => array(
+        'description' => 'The rule group identifier for this group of rules.',
+        'type' => 'int',
+        'size' => 'small',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'rid' => array(
+        'description' => 'The rule identifier for this conditional rule.',
+        'type' => 'int',
+        'size' => 'small',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'source_type' => array(
+        'description' => 'The type of source on which the conditional is based. Currently always "component". Indicates what type of ID the "source" column contains.',
+        'type' => 'varchar',
+        'length' => 128,
+      ),
+      'source' => array(
+        'description' => 'The component ID being used in this condition.',
+        'type' => 'int',
+        'size' => 'small',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'operator' => array(
+        'description' => 'Which operator (equal, contains, starts with, etc.) should be used for this comparison between the source and value?',
+        'type' => 'varchar',
+        'length' => 128,
+      ),
+      'value' => array(
+        'description' => 'The value to be compared with source.',
+        'type' => 'text',
+      ),
+    ),
+    'primary key' => array('nid', 'rgid', 'rid'),
+  );
+
   $schema['webform_emails'] = array(
     'description' => 'Holds information regarding e-mails that should be sent upon submitting a webform',
     'fields' => array(
@@ -1511,6 +1612,119 @@ function webform_update_6331() {
 }
 
 /**
+ * Add the webform_conditional database table.
+ */
+function webform_update_6332() {
+  $ret = array();
+
+  $schema['webform_conditional'] = array(
+    'description' => 'Holds information about conditional logic.',
+    'fields' => array(
+      'nid' => array(
+        'description' => 'The node identifier of a webform.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'rgid' => array(
+        'description' => 'The rule group identifier for this group of rules.',
+        'type' => 'int',
+        'size' => 'small',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'andor' => array(
+        'description' => 'Whether to AND or OR the actions in this group. All actions within the same crid should have the same andor value.',
+        'type' => 'varchar',
+        'length' => 128,
+      ),
+      'action' => array(
+        'description' => 'The action to be performed on the target. Typically "show" or "hide" for targets of type "component", and "send" for targets of type "email".',
+        'type' => 'varchar',
+        'length' => 128,
+      ),
+      'target_type' => array(
+        'description' => 'The type of target to be affected. Either "component" or "email". Indicates what type of ID the "target" column contains.',
+        'type' => 'varchar',
+        'length' => 128,
+      ),
+      'target' => array(
+        'description' => 'The ID of the target to be affected. Typically a component ID.',
+        'type' => 'varchar',
+        'length' => 128,
+      ),
+      'weight' => array(
+        'description' => 'Determines the position of this conditional compared to others.',
+        'type' => 'int',
+        'size' => 'small',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+    'primary key' => array('nid', 'rgid'),
+  );
+
+  $schema['webform_conditional_rules'] = array(
+    'description' => 'Holds information about conditional logic.',
+    'fields' => array(
+      'nid' => array(
+        'description' => 'The node identifier of a webform.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'rgid' => array(
+        'description' => 'The rule group identifier for this group of rules.',
+        'type' => 'int',
+        'size' => 'small',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'rid' => array(
+        'description' => 'The rule identifier for this conditional rule.',
+        'type' => 'int',
+        'size' => 'small',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'source_type' => array(
+        'description' => 'The type of source on which the conditional is based. Currently always "component". Indicates what type of ID the "source" column contains.',
+        'type' => 'varchar',
+        'length' => 128,
+      ),
+      'source' => array(
+        'description' => 'The component ID being used in this condition.',
+        'type' => 'int',
+        'size' => 'small',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'operator' => array(
+        'description' => 'Which operator (equal, contains, starts with, etc.) should be used for this comparison between the source and value?',
+        'type' => 'varchar',
+        'length' => 128,
+      ),
+      'value' => array(
+        'description' => 'The value to be compared with source.',
+        'type' => 'text',
+      ),
+    ),
+    'primary key' => array('nid', 'rgid', 'rid'),
+  );
+
+  db_create_table($ret, 'webform_conditional', $schema['webform_conditional']);
+  db_create_table($ret, 'webform_conditional_rules', $schema['webform_conditional_rules']);
+
+  return $ret;
+}
+
+/**
  * Recursively delete all files and folders in the specified filepath, then
  * delete the containing folder.
  *
diff --git a/webform.module b/webform.module
index 27f10a4..0d5d17b 100644
--- a/webform.module
+++ b/webform.module
@@ -65,6 +65,9 @@ function webform_help($section = 'admin/help#webform', $arg = NULL) {
       $output .= '<p>' . t('This page displays all the components currently configured for this webform node. You may add any number of components to the form, even multiple of the same type. To add a new component, fill in a name and select a type from the fields at the bottom of the table. Submit the form to create the new component or update any changed form values.') . '</p>';
       $output .= '<p>' . t('Click on any existing component\'s name to edit its settings.') . '</p>';
       break;
+    case 'node/%/webform/conditionals':
+      $output .= '<p>' . t('Conditionals may be used to hide or show certain components (or entire pages!) based on the value of other components.') . '</p>';
+      break;
     case 'node/%/submission/%/resend':
       $output .= '<p>' . t('This form may be used to resend e-mails configured for this webform. Check the e-mails that need to be sent and click <em>Resend e-mails</em> to send these e-mails again.') . '</p>';
       break;
@@ -131,6 +134,16 @@ function webform_menu() {
     'weight' => 0,
     'type' => MENU_DEFAULT_LOCAL_TASK,
   );
+  $items['node/%webform_menu/webform/conditionals'] = array(
+    'title' => 'Conditionals',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('webform_conditionals_form', 1),
+    'access callback' => 'node_access',
+    'access arguments' => array('update', 1),
+    'file' => 'includes/webform.conditionals.inc',
+    'weight' => 1,
+    'type' => MENU_LOCAL_TASK,
+  );
   $items['node/%webform_menu/webform/configure'] = array(
     'title' => 'Form settings',
     'page callback' => 'drupal_get_form',
@@ -138,7 +151,7 @@ function webform_menu() {
     'access callback' => 'node_access',
     'access arguments' => array('update', 1),
     'file' => 'includes/webform.pages.inc',
-    'weight' => 2,
+    'weight' => 5,
     'type' => MENU_LOCAL_TASK,
   );
 
@@ -150,7 +163,7 @@ function webform_menu() {
     'access callback' => 'node_access',
     'access arguments' => array('update', 1),
     'file' => 'includes/webform.emails.inc',
-    'weight' => 1,
+    'weight' => 4,
     'type' => MENU_LOCAL_TASK,
   );
   $items['node/%webform_menu/webform/emails/%webform_menu_email'] = array(
@@ -210,6 +223,14 @@ function webform_menu() {
     'type' => MENU_CALLBACK,
   );
 
+  // AJAX callback placeholder for Drupal 6 AHAH callbacks.
+  $items['webform/ajax/callback'] = array(
+    'page callback' => 'webform_ajax_callback',
+    'access callback' => TRUE,
+    'file' => 'includes/webform.pages.inc',
+    'type' => MENU_CALLBACK,
+  );
+
   // Node webform results.
   $items['node/%webform_menu/webform-results'] = array(
     'title' => 'Results',
@@ -578,6 +599,15 @@ function webform_theme() {
       'arguments' => array('element' => NULL),
       'file' => 'includes/webform.components.inc',
     ),
+    // webform.conditionals.inc.
+    'webform_conditional_groups' => array(
+      'arguments' => array('element' => NULL),
+      'file' => 'includes/webform.conditionals.inc',
+    ),
+    'webform_conditional' => array(
+      'arguments' => array('element' => NULL),
+      'file' => 'includes/webform.conditionals.inc',
+    ),
     // webform.pages.inc.
     'webform_advanced_redirection_form' => array(
       'arguments' => array('form' => NULL),
@@ -687,6 +717,13 @@ function webform_elements() {
     '#step' => NULL,
   );
 
+  $elements['webform_conditional'] = array(
+    '#input' => TRUE,
+    '#theme' => 'webform_conditional',
+    '#default_value' => NULL,
+    '#process' => array('webform_conditional_expand'),
+  );
+
   return $elements;
 }
 
@@ -699,9 +736,9 @@ function webform_webform_component_info() {
       'label' => t('Date'),
       'description' => t('Presents month, day, and year fields.'),
       'features' => array(
-        'conditional' => FALSE,
       ),
       'file' => 'components/date.inc',
+      'conditional_type' => 'date',
     ),
     'email' => array(
       'label' => t('E-mail'),
@@ -779,11 +816,13 @@ function webform_webform_component_info() {
       'features' => array(
       ),
       'file' => 'components/number.inc',
+      'conditional_type' => 'numeric',
     ),
     'pagebreak' => array(
       'label' => t('Page break'),
       'description' => t('Organize forms into multiple pages.'),
       'features' => array(
+        'conditional' => FALSE,
         'csv' => FALSE,
         'default_value' => FALSE,
         'description' => FALSE,
@@ -802,6 +841,7 @@ function webform_webform_component_info() {
         'email_address' => TRUE,
         'email_name' => TRUE,
       ),
+      'conditional_type' => 'select',
     ),
     'textarea' => array(
       'label' => t('Textarea'),
@@ -825,14 +865,22 @@ function webform_webform_component_info() {
       'label' => t('Time'),
       'description' => t('Presents the user with hour and minute fields. Optional am/pm fields.'),
       'features' => array(
-        'conditional' => FALSE,
       ),
       'file' => 'components/time.inc',
+      'conditional_type' => 'time',
     ),
   );
 }
 
 /**
+ * Implements hook_webform_conditional_operator_info().
+ */
+function webform_webform_conditional_operator_info() {
+  module_load_include('inc', 'webform', 'includes/webform.conditionals');
+  return _webform_conditional_operator_info();
+}
+
+/**
  * Implements hook_forms().
  *
  * All webform_client_form forms share the same form handler
@@ -998,6 +1046,15 @@ function webform_node_insert($node) {
     }
   }
 
+  // Insert conditionals. Also used with clone.module.
+  if (isset($node->webform['conditionals']) && !empty($node->webform['conditionals'])) {
+    foreach ($node->webform['conditionals'] as $rgid => $conditional) {
+      $conditional['nid'] = $node->nid;
+      $conditional['rgid'] = $rgid;
+      webform_conditional_insert($conditional);
+    }
+  }
+
   // Insert emails. Also used with clone.module.
   if (isset($node->webform['emails']) && !empty($node->webform['emails'])) {
     foreach ($node->webform['emails'] as $eid => $email) {
@@ -1062,6 +1119,24 @@ function webform_node_update($node) {
     }
   }
 
+  // Compare the webform conditionals and don't do anything if it's not needed.
+  if ($original->webform['conditionals'] != $node->webform['conditionals']) {
+    module_load_include('inc', 'webform', 'includes/webform.conditionals');
+
+    // Conditionals don't have unique site-wide IDs or configuration, so our
+    // update here is a bit more aggressive than for components and e-mails.
+    foreach ($original->webform['conditionals'] as $rgid => $conditional) {
+      if (!isset($node->webform['conditionals'][$rgid]) || $original->webform['conditionals'][$rgid] != $node->webform['conditionals'][$rgid]) {
+        webform_conditional_delete($node, $conditional);
+      }
+    }
+    foreach ($node->webform['conditionals'] as $rgid => $conditional) {
+      $conditional['nid'] = $node->nid;
+      $conditional['rgid'] = $rgid;
+      webform_conditional_insert($conditional);
+    }
+  }
+
   // Compare the webform e-mails and don't do anything if it's not needed.
   if ($original->webform['emails'] != $node->webform['emails']) {
     module_load_include('inc', 'webform', 'includes/webform.emails');
@@ -1113,6 +1188,8 @@ function webform_node_delete($node) {
   // Remove any trace of webform data from the database.
   db_query('DELETE FROM {webform} WHERE nid = %d', $node->nid);
   db_query('DELETE FROM {webform_component} WHERE nid = %d', $node->nid);
+  db_query('DELETE FROM {webform_conditional} WHERE nid = %d', $node->nid);
+  db_query('DELETE FROM {webform_conditional_rules} WHERE nid = %d', $node->nid);
   db_query('DELETE FROM {webform_emails} WHERE nid = %d', $node->nid);
   db_query('DELETE FROM {webform_roles} WHERE nid = %d', $node->nid);
   db_query('DELETE FROM {webform_submissions} WHERE nid = %d', $node->nid);
@@ -1229,6 +1306,17 @@ function webform_node_load($node) {
     _webform_components_tree_build($additions['webform']['components'], $component_tree, 0, $page_count);
     $additions['webform']['components'] = _webform_components_tree_flatten($component_tree['children']);
   }
+
+  $additions['webform']['conditionals'] = array();
+  $result = db_query('SELECT * FROM {webform_conditional} WHERE nid = %d ORDER BY weight ASC', $node->nid);
+  while ($c = db_fetch_array($result)) {
+    $additions['webform']['conditionals'][$c['rgid']] = $c;
+  }
+  $result = db_query('SELECT * FROM {webform_conditional_rules} WHERE nid = %d ORDER BY rgid ASC, rid ASC', $node->nid);
+  while ($r = db_fetch_array($result)) {
+    $additions['webform']['conditionals'][$r['rgid']]['rules'][$r['rid']] = $r;
+  }
+
   return $additions;
 }
 
@@ -3368,6 +3456,14 @@ function webform_component_implements($type, $callback) {
 }
 
 /**
+ * Form API #process function to expand a webform conditional element.
+ */
+function webform_conditional_expand($element) {
+  module_load_include('inc', 'webform', 'includes/webform.conditionals');
+  return _webform_conditional_expand($element);
+}
+
+/**
  * Disable the Drupal page cache.
  */
 function webform_disable_page_cache() {
