Skip to content

Conversation

@yujiteshima
Copy link
Contributor

Pull Request

Title: Fix noscript style evaluation during navigation

Summary

Fixes #1464

This PR prevents Turbo from incorrectly evaluating <style> tags nested within <noscript> elements during page navigation.

Problem

Turbo's page rendering mechanism was evaluating content inside <noscript> elements, causing:

  • Styles intended only for non-JavaScript environments to be applied
  • Content to become hidden when display: none styles were applied during navigation

Solution

The fix deactivates <noscript> elements by converting their innerHTML to textContent in two critical places:

  1. PageRenderer (page_renderer.js): Before adopting the new body element
  2. PageSnapshot (page_snapshot.js): When creating cached snapshots

This conversion prevents browsers from parsing nested HTML/CSS while preserving the content as plain text.

Testing

Added a new test case that verifies styles inside <noscript> elements are not evaluated during Turbo navigation.

Reproduction Projects

Prevent Turbo from evaluating <style> tags inside <noscript> elements
during page rendering and snapshot creation by converting innerHTML to
textContent. This fixes an issue where noscript styles would incorrectly
be applied during navigation, potentially hiding page content.
@yujiteshima
Copy link
Contributor Author

Note on CI Failure

The CI failure appears to be from a pre-existing flaky test, not related to this PR's changes.

The flaky test: navigation_tests.js:451 - "does not fire turbo:load twice after following a redirect"

I tested this on upstream/main (before my changes) and got the same intermittent failures - it passes about 80% of the time. The test added in this PR for the noscript fix passes consistently (5/5 runs).

The noscript fix itself is working correctly and the new test coverage is stable. Happy to re-run CI or provide more details if needed!

Copy link
Contributor

@packagethief packagethief left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @yujiteshima. This looks good. Just one (possibly silly) question. If turbo is controlling navigation we know that JavaScript is enabled, so any <noscript> element is irrelevant anyway. Instead of converting the element contents to text, could we just remove the element?

removeNoscriptElements() {
  for (const noscriptElement of this.newElement.querySelectorAll("noscript")) {
    noscriptElement.remove()
  }
}

@yujiteshima
Copy link
Contributor Author

@packagethief Thank you for the suggestion—not silly at all! I agree that removing <noscript> elements is a better approach.

Since Turbo is running, JavaScript is demonstrably enabled, making <noscript> elements unnecessary. There's no practical reason for code to depend on <noscript> elements in a JavaScript-enabled environment, so removing them keeps the DOM cleaner and aligns better with Turbo's philosophy of progressive enhancement.

I'll update the implementation to use removeNoscriptElements() instead of deactivateNoscriptElements().

Since Turbo controls navigation only when JavaScript is enabled,
noscript elements are unnecessary and can be removed entirely
instead of converting their content to text.

This approach keeps the DOM cleaner and better aligns with
Turbo's progressive enhancement philosophy.
Since Turbo controls navigation only when JavaScript is enabled,
noscript elements are unnecessary and can be removed entirely.

The removal happens after document.adoptNode() to ensure consistent
behavior across browsers, particularly Firefox.
@yujiteshima
Copy link
Contributor Author

@packagethief Updated! The implementation now removes <noscript> elements entirely using removeNoscriptElements().

The removal happens after document.adoptNode() to ensure consistent behavior across browsers—Firefox requires the element to be adopted into the current document before removal to prevent unintended style evaluation.

All tests are passing on both Chrome and Firefox.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Rails: Link navigation causes <style> inside <noscript> to be evaluated

2 participants