I have a content type that has a series of multi-value select fields. That I need users to select in relation to a value pulled from another node.

The best way to present this is to have a table that looks like this:

enter image description here

I've got the 'bones' of a hook_form_alter, and I can almost present what I need. However, I cannot seem to get my checkboxes/radios to appear in the grid. I am this far...

enter image description here

My form_alter function looks like:

function hnbuilder_form_node_scheme_of_work_form_alter(&$form, FormStateInterface &$form_state, &$form_id){
/** check whether we passed a node reference into the form via ID in the url **/
if ($_GET['id']){
    $nid = $_GET['id'];
    /** if we didn't pass it in, we are editing the node **/
    $current_url = Url::fromRoute('<current>');
    $path = $current_url->getInternalPath();
    $path_args = explode('/', $path);
    $thisnid = $path_args[1];
    $thisnode = \Drupal\node\Entity\Node::load($thisnid);
    $nid = $thisnode->get('field_related_unit')->target_id;
/** Load the referenced node */
$node = \Drupal\node\Entity\Node::load($nid);

/** get the learning outcomes from the referenced node 
    and put them into an array **/
$lo = array(
    1=>"LO1 ".$node->field_lo1->value,
    2=>"LO2 ".$node->field_lo2->value,
    3=>"LO3 ".$node->field_lo3->value,
    4=>"LO4 ".$node->field_lo4->value

/** create table headers **//
$header = array(
    0 => 'Learning Outcome',
    1 => 'Assignment 1',
    2 => 'Assignment 2',
    3 => 'Assignment 3',
    4 => 'Assignment 4'

/** an array of the checkbox/radio options from our content type
    each field has 4 options

$ffld = array(

/** create a new array of options for the table

$options = array(

/** build the tableselect **/
$form['table'] = array(
    '#type' => 'tableselect',
    '#header' => $header,
    '#options' => $options,
    '#js_select' => FALSE

return $form;


I think I have several issues, and I'm hoping someone can help:

  1. I'm not sure that 'tableselect' is the right thing to be using, as it seems this only supports single selection (based on the table row).
  2. I'm unsure how to display the existing checkbox/radios as actual field items. I'm stuck getting their values.

Is there a way to achieve this? If so, I'd really appreciate some pointers.

1 Answer 1


I think you can define a wrapper element as type table. The core user permissions form does this, and I think is similar to what you're trying to build:

 $form['permissions'] = [
  '#type' => 'table',
  '#header' => [
  '#id' => 'permissions',
  '#attributes' => [
    'class' => [
  '#sticky' => TRUE,
foreach ($role_names as $name) {
  $form['permissions']['#header'][] = [
    'data' => $name,
    'class' => [

In your case, I think you'd define something like $form['sow'] as a '#type' => 'table' which will be a wrapper element that all the checkbox (or radios) appear under.

Then loop through your fields (these will be similar to how the user permission form loops through each permission, creating a row).

foreach ($fields as $low) {
  $form['sow'][$low]['description'] = [
    '#type' => 'item',
    '#title' => $low['title'],
    '#description' => ...,

  // Now loop through each assignment. This will be similar
  // to how the user permission form loops through each role
  // for each permission.
  foreach ($assignments as $assignment) {
    $form['sow'][$low][$assignment] = [
      '#type' => 'checkbox', // Or 'radio', depending on the need.
      // Other form element details here too.

Then, for each assignment (these will behave similar to each role in the user permission form)

  • Thanks for the help. I'm somewhat new to this. I can sort of see what you are saying, but I can't seem to get my #options to appear in the table cells. Can you give me an idea of how to iterate through $form['field_lo1_sow'] to display each radio in a table cell? I've tried a number of different things and keep getting blank cells. Many thanks
    – gmak
    Commented Jan 20, 2018 at 10:58
  • I added some additional details to the above code.
    – jhedstrom
    Commented Jan 22, 2018 at 16:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.