Running ajax callbacks on custom composite field I am using a custom composite field("test") in drupal8 webform in a webform_form_alter() hook. Two select fields-"out_part" and "out_serial" are added to this composite field("test"). "out_serial" is dependent on "out_part" i.e. upon selecting an out_part value from the dropdown, the dropdown values of out_serial are generated. I was able to achieve this with ajax callbacks.

    $form['elements']['test']['#element'] = array(
    'out_part' =&gt; array(
            '#type' =&gt; 'select',
            '#id' =&gt; 'out_part',
            '#options' =&gt; array(
                '80002192'=&gt;'80002192',
                '80002191'=&gt;'80002191'
                ),
            '#ajax' =&gt; array(
                'event' =&gt; 'change',
                'wrapper' =&gt; 'serialNumber_wrapper',
                'callback'=&gt; 'populateOutSerialNumbers',
                'method'=&gt; 'replace'
                )
            ),
    'out_serial' =&gt; array(
            '#type' =&gt; 'select',
            '#id' =&gt; 'out_serial',
            '#validated' =&gt; TRUE,
            '#attributes' =&gt; [
                                'id' =&gt; ['serialNumber_wrapper'],
                              ],
            ));         

    function populateOutSerialNumbers($form, $form_state){
        $partNumber = $form_state-&gt;getValue('test')[1]['out_part'];
        $partNumber = isset($partNumber) ? $partNumber : 'Onboard';

        // Update the $result with dynamic database query results with respect to selected out_part
        Drupal\Core\Database\Database::setActiveConnection('***');  
        $db = Drupal\Core\Database\Database::getConnection();
        $query = $db-&gt;query("select distinct T1.serialnumber from assets T1 where T1.dbid &lt;&gt; 0 and (T1.manufacturerpartno = :partNumber)", [':partNumber' =&gt; $partNumber]);
        $result = $query-&gt;fetchAllKeyed(0,0);

        $form['elements']['test']['#element']['out_serial']['#options'] = $result;

        db_set_active();
        return $form['elements']['test']['#element']['out_serial'];
    }                                                               


This callback works only on the first set of values of the custom composite field. When I click on "Add", the ajax fails to work on the second set of values. Any suggestions on how to overcome this? Do I need to add the ajax to 
    $form['elements']['test']['items'] ?
You can not modify the $form in the ajax callback. The option for the element out_serial should be set inside form build not in ajax callback. Try with following approach:

// Inside your form build or alter function.
$form['elements']['test']['#element'] = array(
  'out_part' =&gt; array(
    '#type' =&gt; 'select',
    '#id' =&gt; 'out_part',
    '#options' =&gt; array(
      '80002192'=&gt;'80002192',
      '80002191'=&gt;'80002191'
    ),
    '#ajax' =&gt; array(
      'event' =&gt; 'change',
      'wrapper' =&gt; 'serialNumber_wrapper',
      'callback'=&gt; 'populateOutSerialNumbers',
      'method'=&gt; 'replace'
      )
    ),
  'out_serial' =&gt; array(
    '#type' =&gt; 'select',
    '#id' =&gt; 'out_serial',
    '#validated' =&gt; TRUE,
    '#attributes' =&gt; [
        'id' =&gt; ['serialNumber_wrapper'],
      ],
    )
);         

// Set value here as when you return the element in ajax callback.
// the form will come here again for rebuild with $form_state having filled values.
if (!empty($form_state-&gt;getValue('test'))) {
  $partNumber = $form_state-&gt;getValue('test')[1]['out_part'];
  $partNumber = isset($partNumber) ? $partNumber : 'Onboard';

  // Update the $result with dynamic database query results with respect to selected out_part
  Drupal\Core\Database\Database::setActiveConnection('***');  
  $db = Drupal\Core\Database\Database::getConnection();
  $query = $db-&gt;query("select distinct T1.serialnumber from assets T1 where T1.dbid &lt;&gt; 0 and (T1.manufacturerpartno = :partNumber)", [':partNumber' =&gt; $partNumber]);
  $result = $query-&gt;fetchAllKeyed(0,0);

  $form['elements']['test']['#element']['out_serial']['#options'] = $result;

  db_set_active();
}
// End of your build or form alter function.

/**
 * Ajax callback of out_part element.
 */
function populateOutSerialNumbers($form, $form_state){
  return $form['elements']['test']['#element']['out_serial'];
}