Submitted by Chris McIntosh on July 2, 2024

In Drupal 8, Drupal 9 or Drupal 10 creating custom forms is a common task for developers. A useful feature is to include a select dropdown within a table row, allowing users to interact with the form elements in an organized manner. This blog post will guide you through the process of creating a custom form that includes a select dropdown rendered within a table.

Step-by-Step Guide

Step 1: Set Up Your Custom Module

First, create a custom module. For this example, we'll call it `custom_table_form`.

File Structure

custom_table_form/
  - custom_table_form.info.yml
  - custom_table_form.module
  - src/
    - Form/
      - ExampleForm.php

Module Info File (`custom_table_form.info.yml`)

name: 'Custom Table Form'
type: module
description: 'A module that provides a custom form with a select dropdown rendered in a table.'
core_version_requirement: ^8 || ^9
package: Custom
dependencies:
  - drupal:system

Step 2: Implement the Custom Form

Next, create the form class that will build the form and handle form submissions.

Form Class (`src/Form/ExampleForm.php`)

```php
<?php

namespace Drupal\custom_table_form\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

class ExampleForm extends FormBase {

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'custom_table_form_example_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    // Define a sample list of items for demonstration.
    $items = [
      ['id' => 1, 'name' => 'Item 1'],
      ['id' => 2, 'name' => 'Item 2'],
    ];

    // Define the form table.
    $form['items'] = [
      '#type' => 'table',
      '#header' => [
        $this->t('Item'),
        $this->t('Current Status'),
        $this->t('Update Status'),
      ],
      '#empty' => $this->t('No items found.'),
    ];

    // Add rows to the table.
    foreach ($items as $item) {
      $form['items'][$item['id']]['item'] = [
        '#type' => 'markup',
        '#markup' => $item['name'],
      ];

      $form['items'][$item['id']]['current_status'] = [
        '#type' => 'markup',
        '#markup' => 'Active', // Example status, typically fetched from item data.
      ];

      $form['items'][$item['id']]['update_status'] = [
        '#type' => 'select',
        '#options' => [
          'active' => $this->t('Active'),
          'inactive' => $this->t('Inactive'),
        ],
        '#default_value' => 'active',
      ];
    }

    // Add a submit button to the form.
    $form['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Save'),
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    // Handle form submission.
    $values = $form_state->getValue('items');
    foreach ($values as $item_id => $item_data) {
      $new_status = $item_data['update_status'];
      \Drupal::messenger()->addMessage($this->t('Item ID @id has been updated to status: @status', ['@id' => $item_id, '@status' => $new_status]));
    }
  }
}
```

Step 3: Define the Route

Now, define the route to access your form.

Routing File (`custom_table_form.routing.yml`)


custom_table_form.example_form:
  path: '/custom-table-form'
  defaults:
    _form: '\Drupal\custom_table_form\Form\ExampleForm'
    _title: 'Custom Table Form'
  requirements:
    _permission: 'access content'

Step 4: Enable the Module

Navigate to the Extend page (`/admin/modules`) in your Drupal site and enable the "Custom Table Form" module.

Step 5: Access the Form

Visit `/custom-table-form` in your browser. You should see the form with a table listing items and a select dropdown in each row to update the status.