Common Issues
apps/docs/src/content/docs/drupal/common-issues Click to copy apps/docs/src/content/docs/drupal/common-issues Quick-reference for the most frequently encountered HELiX + Drupal problems. Each entry includes the symptom, root cause, and the fix in a copy-paste format.
For detailed diagnostic walkthroughs, see Troubleshooting.
Issue 1: CDN 404 — Component Script Not Found
Section titled “Issue 1: CDN 404 — Component Script Not Found”Symptom: DevTools Network tab shows 404 for the component URL. Raw <hx-button> tags visible on page.
Cause: Incorrect CDN URL or outdated version number in the library YAML.
Fix:
# mytheme.libraries.yml — use the correct versioned URLhelix-button: version: 1.1.2 js: https://cdn.jsdelivr.net/npm/@helixui/library@3.9.0/dist/components/hx-button/index.js: type: external preprocess: false attributes: type: module crossorigin: anonymousFull bundle alternative:
https://cdn.jsdelivr.net/npm/@helixui/library@3.9.0/dist/index.jsThen drush cr.
Issue 2: Missing type: module — Import Syntax Error
Section titled “Issue 2: Missing type: module — Import Syntax Error”Symptom: Console error: Uncaught SyntaxError: Cannot use import statement outside a module
Cause: The <script> tag does not have type="module". ES modules require it.
Fix:
helix-button: js: dist/components/hx-button/index.js: preprocess: false attributes: type: module # This is required — without it, the file is treated as a classic scriptdrush cr after editing.
Issue 3: hx-size vs size Confusion
Section titled “Issue 3: hx-size vs size Confusion”Symptom: Setting size="lg" on a HELiX component has no effect.
Cause: HELiX uses hx-size (not the native HTML size) to avoid conflicts with native form element attributes like <input size="...">.
Fix:
{# Wrong #}<hx-button size="lg">Submit</hx-button><hx-avatar size="sm"></hx-avatar>
{# Correct #}<hx-button hx-size="lg">Submit</hx-button><hx-avatar hx-size="sm"></hx-avatar>Issue 4: Library Not Attaching to Pages
Section titled “Issue 4: Library Not Attaching to Pages”Symptom: Components work on some pages but not others. Console shows customElements.get('hx-card') returns undefined on affected pages.
Cause: Library is attached via template or preprocess for one content type but not all pages that use the component.
Fix — Global attachment for components used site-wide:
libraries: - mytheme/helix-button # Used in navigation on every page - mytheme/helix-tokens # CSS custom properties — always loadFix — Template-specific attachment:
{# node--article--teaser.html.twig #}{{ attach_library('mytheme/helix-card') }}Fix — Preprocess for route-based attachment:
function mytheme_preprocess_page(array &$variables): void { $route = \Drupal::routeMatch()->getRouteName(); if (str_starts_with($route, 'entity.node.canonical')) { $variables['#attached']['library'][] = 'mytheme/helix-content'; }}Issue 5: AJAX Not Re-Initializing Components
Section titled “Issue 5: AJAX Not Re-Initializing Components”Symptom: Drupal AJAX replaces a region. New <hx-card> elements in the replaced region do not upgrade or do not have their event listeners.
Cause: Drupal Behaviors are re-attached to the replaced region automatically, but your behavior may not be using once() with the context parameter correctly, or the component library was never loaded for AJAX responses.
Fix — Use once() with context:
Drupal.behaviors.helixCard = { attach(context) { // context = the replaced DOM subtree on AJAX. // Scope to hx-href cards — hx-card only fires hx-click when // it is the interactive variant (i.e. has hx-href). once('hx-card-events', 'hx-card[hx-href]', context).forEach((card) => { card.addEventListener('hx-click', handleCardClick); }); },};Fix — Ensure library is attached to AJAX response:
$response = new AjaxResponse();$response->addCommand(new HtmlCommand('#target', [ '#markup' => '<hx-card>...</hx-card>', '#attached' => ['library' => ['mytheme/helix-card']],]));Issue 6: once() Double-Initialization
Section titled “Issue 6: once() Double-Initialization”Symptom: Event handlers fire twice. Behaviors run twice on the same element. Console logs appear doubled after AJAX.
Cause: once() is called without the context parameter, or the namespace key conflicts with another behavior.
Fix — Always pass context:
Drupal.behaviors.helixCard = { attach(context) { // Provide a unique namespace key ('hx-card-events') + the context once('hx-card-events', 'hx-card', context).forEach((card) => { // Only runs once per element, per namespace card.addEventListener('hx-click', handler); }); },};Fix — Use unique namespace keys across behaviors to avoid collisions.
Issue 7: CSP Blocking ES Modules
Section titled “Issue 7: CSP Blocking ES Modules”Symptom: Console CSP violation: Refused to load the script 'https://cdn.jsdelivr.net/...'
Cause: Content Security Policy does not allow scripts from external CDN origins.
Fix:
$config['security_kit.settings']['seckit_xss']['csp']['script-src'] = [ "'self'", 'https://cdn.jsdelivr.net',];Or configure Security Kit at Admin → Configuration → Security → Security Kit.
Alternative fix — Use local npm build instead of CDN to avoid external origins entirely. See npm Installation.
Issue 8: Shadow DOM CSS Not Applying
Section titled “Issue 8: Shadow DOM CSS Not Applying”Symptom: You added CSS targeting hx-button .inner-element and it has no effect. The component looks unstyled.
Cause: Shadow DOM encapsulation prevents external CSS selectors from reaching inside the component’s shadow root.
Fix — Use CSS custom properties that inherit through Shadow DOM boundaries:
/* Wrong — cannot pierce Shadow DOM */hx-button button { background-color: red;}
/* Correct — CSS custom properties inherit through Shadow DOM */hx-button { --hx-button-bg: var(--hx-color-action-primary-bg); --hx-button-color: var(--hx-color-text-on-primary);}Check each component’s documentation (or its CEM entry) for its exposed --hx-* CSS custom
properties — the component-level tokens (e.g. --hx-button-bg) fall back to the semantic action
tokens (e.g. --hx-color-action-primary-bg), which fall back to the primitive palette.
Issue 9: Drupal Aggregation Breaking Components
Section titled “Issue 9: Drupal Aggregation Breaking Components”Symptom: Components work with Drupal’s JS aggregation disabled, fail when enabled.
Cause: Drupal concatenates JS files during aggregation. This breaks ES module import statements.
Fix:
helix-button: js: dist/components/hx-button/index.js: preprocess: false # Opt out of aggregation — required for ALL ES modules minified: true attributes: type: moduleSet preprocess: false on every HELiX library entry. Then drush cr.
Issue 10: Form Value Not Submitted
Section titled “Issue 10: Form Value Not Submitted”Symptom: $form_state->getValue('field_name') returns null or empty. The component’s value is not in $_POST.
Cause (most common): Missing name attribute on the component. Without name, ElementInternals.setFormValue() has no key to submit under.
Fix:
{# Wrong — no name attribute #}<hx-text-input label="Email Address"></hx-text-input>
{# Correct #}<hx-text-input name="email" label="Email Address"></hx-text-input>Cause (less common): Component is not inside a <form> element. ElementInternals form association requires the component to be a DOM descendant of the form.
Verify association in console:
document.querySelector('hx-text-input[name="email"]')?.form;// Returns <form> element if correctly associated, null if notQuick Diagnostic Commands
Section titled “Quick Diagnostic Commands”# Clear all Drupal cachesdrush cr
# Verify library is discoverabledrush eval "print_r(\Drupal::service('library.discovery')->getLibrariesByExtension('mytheme'));"
# Check page for type=module script tagscurl -s https://your-site.com/some-page | grep 'type="module"'// Browser console — run on any page with a HELiX componentconst checks = ['hx-button', 'hx-card', 'hx-text-input', 'hx-select'];checks.forEach(tag => { const defined = customElements.get(tag) ? 'registered' : 'MISSING'; const el = document.querySelector(tag); const upgraded = el?.shadowRoot ? 'upgraded' : (el ? 'NOT upgraded' : 'not on page'); console.log(`${tag}: ${defined}, ${upgraded}`);});Related
Section titled “Related”- Troubleshooting — Full diagnostic walkthroughs per symptom
- Installation: CDN — Correct library YAML setup
- Behaviors —
once()API reference