14

I want add link field (label + url internal/external) in custom form

This not work:

$form['test_ink'] = array(
  '#type' => 'link',
  '#title' => $this->t('Link title'),
  '#url' => '',
);

5 Answers 5

16

The link (Link) render element type is used to render an anchor element on a page, and not used to provide an input element in a form that is constrained for URLs.

As an example you may look at LinkWidget::formElement, which shows how that field widget creates form elements for a Link field. And the way it does this is to use the url (Url) form element, which will provide an input element that validates URLs. Make sure that the #url property is a valid (Url) object.

use Drupal\Core\Url;

$form['test_link'] = [
  '#type' => 'url',
  '#title' => $this->t('Link title'),
  // Example of a Url object from a route. See the documentation
  // for more methods that may help generate a Url object.
  '#url' => Url::fromRoute('entity.node.canonical', ['node' => 1]),
];

Edit:

  1. Added @imclean's suggestion to the answer for readability
3
  • 3
    Note that for internal links the url type is not used, rather the entity_autocomplete.
    – Tim
    Feb 22, 2017 at 9:23
  • 2
    Note that you can also use the linkit element if you have the linkit module (see drupal.org/project/linkit): $form['test_ink'] = [ '#type' => 'linkit', '#autocomplete_route_name' => 'linkit.autocomplete', '#autocomplete_route_parameters' => [ 'linkit_profile_id' => 'default', ], ]
    – mpp
    Jul 17, 2019 at 14:23
  • 2
    Make sure the URL is a URL object or it simply won't work. For example: use Drupal\Core\Url; $element['test_link'] = [ '#type' => 'link', '#title' => t('Link title'), '#url' => Url::fromRoute('entity.node_type.collection'), ];
    – imclean
    Aug 23, 2019 at 2:28
5

I liked @mpp's answer on how to create a linkit field if you have Linkit module enabled. His example was not code formatted, so this is just a repost using formatted code for better readability and to make it easier to copy paste this to use in your own projects. Create a linkit field with Drupal's form api:

$form['block_link'] = [
  '#type' => 'linkit',
  '#title' => $this->t('Select link target'),
  '#description' => $this->t('Start typing to see a list of results. Click to select.'),
  '#autocomplete_route_name' => 'linkit.autocomplete',
  '#autocomplete_route_parameters' => [
    'linkit_profile_id' => 'default',
  ],
  '#default_value' => isset($config['block_link']) ? $config['block_link'] : '',
];

Note that you can change 'default' to any linkit profile you might have in your project. Also note: my default value in this case comes from a block config form because I added this linkit field to a block's settings page. Remove #default_value if it is not applicable to your case or change it depending on where you get your value from.

2

For anyone stumbling across this post looking at adding Linkit to a config form (thanks @mpp and @Flyke), there's been a slight change in the API: 'linkit_profile_id' => 'default', should now be 'linkit_profile' => 'default',

 $form['block_link'] = [
  '#type' => 'linkit',
  '#title' => $this->t('Select link target'),
  '#description' => $this->t('Start typing to see a list of results. Click to select.'),
  '#autocomplete_route_name' => 'linkit.autocomplete',
  '#autocomplete_route_parameters' => [
    'linkit_profile' => 'default',
  ],
  '#default_value' => isset($config['block_link']) ? $config['block_link'] : '',
];

Small point but worth knowing.

1

I was facing this problem when I needed to add a link (url+label) to the theme settings form. I didn't use the url field cause it has a bug if the user wants to add an internal link.

This is how it looked on the CMS:

enter image description here

This is the code:

/**
 * Implements hook_form_system_theme_settings_alter().
 **/
function francisco_form_system_theme_settings_alter(&$form, \Drupal\Core\Form\FormStateInterface &$form_state, $form_id = NULL) {
  // Work-around for a core bug affecting admin themes. See issue #943212.
  if (isset($form_id)) {
    return;
  }

  $form['francisco_theme_option_sidebar'] = array(
    '#type' => 'details',
    '#title' => t('Sidebar'),
    '#description' => t('Lorem ipsum.'),
    '#open' => TRUE,
  );

  $form['francisco_theme_option_sidebar']['francisco_theme_option_sidebar_footer_cta_title'] = array(
    '#type'          => 'textfield',
    '#title'         => t('Link Title'),
    '#default_value' => theme_get_setting('francisco_theme_option_sidebar_footer_cta_title'),
    '#description'   => t("Lorem ipsum."),
    '#maxlength' => 255
  );

  $form['francisco_theme_option_sidebar']['francisco_theme_option_sidebar_footer_cta_url'] = array(
    '#type'          => 'textfield',
    '#title'         => t('URL'),
    '#default_value' => theme_get_setting('francisco_theme_option_sidebar_footer_cta_url'),
    '#description'   => t("Lorem ipsum."),
    '#maxlength' => 2048,
  );

}
0

To add link field (label + url internal/external) & core link widget's url field validation in custom form:

$form['resource_fieldset']['design_tool_link'] = [
  '#type' => 'entity_autocomplete',
  '#target_type' => 'node',
  '#title' => $this->t('Design Tool Link'),
  '#description' => $this->t('Select Design Tool Link'),
  '#required' => TRUE,
  '#element_validate' => [
    [
      'Drupal\link\Plugin\Field\FieldWidget\LinkWidget',
      'validateUriElement',
    ],
  ],
  '#attributes' => [
    'data-autocomplete-first-character-blacklist' => '/#?',
  ],
  '#process_default_value' => FALSE,
  '#default_value' => $design_tool_link ?? : '',
];

 $form['resource_fieldset']['title'] = [
  '#type' => 'textfield',
  '#title' => $this->t('Title'),
];

Note: by adding #element_validate attribute :

  • Custom Url field 'll accept external & internal links as default core link widget's URL field do
  • Also validation of core link 'll applied instead of writing same validation again

Your Answer

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

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