You are here

Drupal 8 Programmatic Alternate Text

Having alt text on your images is a very good thing for accessibility, and a requirement for a lot of websites in order to comply with WCAG standards for ADA compliance. However, people are not very good at remembering to add alt text or don't think they have the time to craft good alt text. So, what happens is alt gets ignored or bogus content gets put into the field. As a developer I want to help these people do the right thing and, if I can, prevent them from having to do repeitive work.

In this example we have a user profile with a profile picture field. This profile picture field needs to have alt text. However, since we are sure this image is going to be a profile picture, the alt text should just be their name. There is already a field in the content type for their name, so requring the user to write their name a second time on the form is redundant. We can improve this experience by automatically making the alt value the same as the name value. Also, we should not allow them to change the alt value to something silly.

Here is a screenshot of the form as default in Drupal:

Profile node form showing name, body, and profile picture fields with required alt text.

Copying Name into Alternative Text

First thing we want to do is automatically set the alternative text value to what the user entered in the name field. In this case the name field is actually the node title. To do this, we are going to copy the value of the name/title field to the alt text right before Drupal saves it to the database. We'll use hook_entity_presave() in our module's .module file (mymodule.module in this case).

/**
 * Implements hook_entity_presave().
 *
 * Before Drupal saves the entity, it will run this code.
 */
function mymodule_entity_presave(Drupal\Core\Entity\EntityInterface $entity) {
  // We want to limit this to only people profile images.
  if ($entity->bundle() == 'profile') {

    // Get the value array for our field so we can alter it.
    $alt = $entity->get("field_profile_picture")->getValue();

    // Replace the alt text to the title of this entity.
    $alt[0]['alt'] = $entity->getTitle();

    // Save the value array back to entity.
    $entity->set('field_profile_picture', $alt);
  }
}

Excellent! Now when we save the node, the alt text gets set to their name. However we have a bit of a usiblity problem. The alt text field is there for the user to change, but after they submit it will not take the value they provide.

Hide the alternative text field

In this case, we're going to use the heavy hammer and remove their ability to use the alternative text part of the profile picture field. The user will not have another field to worry about. To do this we will define a process callback in hook_field_widget_multivalue_form_alter(). In the callback we will set the element's access to FALSE. This will keep the field and the data, but not show it to the user.

/**
 * Implements hook_field_widget_multivalue_form_alter().
 *
 * Here we tell Drupal that when we want to run some code when the field widget gets built.
 */
function mymodule_field_widget_multivalue_form_alter(&$elements, \Drupal\Core\Form\FormStateInterface $form_state, $context) {
  // We only want to mess with field_profile_picture
  if ($context['items']->getName() == 'field_profile_picture') {

    // If this is a multivalue field, we want to modify every instance of the field on the form,
    // so we iterate.
    foreach (\Drupal\Core\Render\Element::children($elements) as $key => $child) {

      // Set a custom function that will run when processing this widget.
      $elements[$key]['#process'][] = '_mymodule_remove_alt_field';
    }
  }
}

/**
 * #process callback for disabling alt on image field.
 * Defined in mymodule_field_widget_multivalue_form_alter().
 */
function _mymodule_remove_alt_field($form_element, \Drupal\Core\Form\FormStateInterface $form_state) {
  $form_element['alt']['#access'] = FALSE;

  return $form_element;
}

Once we get this done, we are done. The user will not see an alternative text field, the value for alternative text gets set to what they provided in the name/title field.

Profile node form showing name, body and profile picture fields without the alt text field.