Attaching assets if the page contains a table I want to attach a CSS file to a page only if it contains a table. I tried

function my_assets_element_info_alter(array &amp;$types) {
  if (isset($types['table'])) {
    $types['table']['#attached']['library'][] = 'my_assets/fancy';
  }
}


from the guide "Adding stylesheets (CSS) and JavaScript (JS) to a Drupal 8 module" but it does not work. The hook itself and the condition works. The question is where I have to save the #attached array in the $types variable?

I appreciate your help and feedback.

PS: The following hook attaches the CSS as expected:

function my_assets_page_attachments(array &amp;$attachments) {
  $attachments['#attached']['library'][] = 'my_assets/fancy';
}


Edit: While using the site I noticed that my CSS loads on sites like "/admin/structure/types". The Twig Debug hint says "THEME HOOK: 'table'". I guess this is important because it does not say this on the other tables I was waiting for to load the CSS.
'#type' =&gt; 'table'

OK, so I tried it out in a Vanilla D8.6 with a custom module like yours and the Bartik theme enabled. I placed hook_element_info_alter in the custom module and checked what Kint ksm($info) would return me (matching the code from your question that would be ksm($types)). I visited the front page and I saw 'table' in the array so I thought there must be a table on that page somewhere and the library should get attached. But it didn't. Because there actually was no table.

Only after I added a custom block to the custom module, placed the block somewhere prominent and let it output some sample code from class Table:

/**
 * {@inheritdoc}
 */
public function build() {
  $build = [];
  $build['contacts'] = [
    '#type'    =&gt; 'table',
    '#caption' =&gt; $this
      -&gt;t('Sample Table'),
    '#header'  =&gt; [
      $this
        -&gt;t('Name'),
      $this
        -&gt;t('Phone'),
    ],
  ];
  return $build;
}


And then the library suddenly got attached as documented. So, yeah, everything's fine. You just need to be sure you really have a '#type' =&gt; 'table' element on that page. That's all.



'#theme' =&gt; 'table'

As @4k4 asked in the comments to your question it seems likely you used '#theme' =&gt; 'table' to build your tables. Then attach the library directly like that (snipped copied from the Node core module):

$build['node_revisions_table'] = [
  '#theme' =&gt; 'table',
  '#rows' =&gt; $rows,
  '#header' =&gt; $header,
  '#attached' =&gt; [
    'library' =&gt; ['node/drupal.node.admin'],
  ],
  '#attributes' =&gt; ['class' =&gt; 'node-revision-table'],
];


Although in this case you could also make use of hook_preprocess_table to have that pattern applied to all tables you've built using '#theme' =&gt; 'table'.

/**
 * Implements hook_preprocess_HOOK().
 */
function my_assets_preprocess_table(&amp;$variables) {
  $variables['#attached']['library'][] =  'my_assets/fancy';
}




&lt;table&gt;

OK, so after we finally found out you put a table as markup into the body field of your node, using CKEditor, here's what's needed to attach your library accordingly.

You can't check for '#type' =&gt; 'table' or '#theme' =&gt; 'table' at this point, as your table is just markup. So simply check for the existence of a &lt;table&gt; tag. Or even better, check for just &lt;table, because who knows what else attributes can come after that. Pay attention for the two underscores in the function name, and replace body with the machine name of whatever field you need to preprocess.

/**
 * Implements template_preprocess_field__FIELD_NAME().
 */
function my_assets_preprocess_field__body(&amp;$variables) {

  /** @var \Drupal\Core\Field\FieldItemListInterface $items */
  $items = $variables['element']['#items'];

  $value = $items-&gt;first()-&gt;getValue()['value'];

  if (\strpos($value, '&lt;table') !== FALSE) {
    $variables['#attached']['library'][] = 'my_assets/fancy';
  }
}