To get this working I had to create a hidden field to store the value and use a custom selectHandler applied via class.
JavaScript File
(function ($, Drupal) {
'use strict';
/**
* Override drupal selectHandler function
*/
function customSelectHandler(event, ui) {
var valueField = $(event.target);
if($(event.target).hasClass('MYCUSTOM-autocomplete')) {
var valueFieldName = event.target.name+'_value';
if($('input[name='+valueFieldName+']').length > 0) {
valueField = $('input[name='+valueFieldName+']');
// update the labels too
const labels = Drupal.autocomplete.splitValues(event.target.value);
labels.pop();
labels.push(ui.item.label);
event.target.value = labels.join(', ');
}
}
const terms = Drupal.autocomplete.splitValues(valueField.val());
// Remove the current input.
terms.pop();
// Add the selected item.
terms.push(ui.item.value);
valueField.val(terms.join(', '));
// Return false to tell jQuery UI that we've filled in the value already.
return false;
}
Drupal.behaviors.myCustomAutocomplete = {
attach: function(context, settings) {
// attach custom select handler to fields with class
$('input.MYCUSTOM-autocomplete').autocomplete({
select: customSelectHandler,
});
}
};
})(jQuery, Drupal);
Form PHP
$form['my_field'] = array(
'#type' => 'textfield',
'#attributes' => ['class' => ['MYCUSTOM-autocomplete'],],
'#autocomplete_route_name' => 'mymodule.myfield_autocomplete',
);
// field value
$form['my_field_value'] = array(
'#type' => 'hidden',
);
On our forms we also have an AJAX callback on the autocompleteselect event, and I've noticed the value for the hidden field is blank but the userInput on the $form_state has the value.
Problem with this is the splitValues function may not work well for the labels, since it appears to be comma-delimited. You may want to write your own to handle it. It also won't work well if using the same form twice on a page, but there may be a way to narrow down the selector on the hidden field.