Skip to content

no-forbidden-elements: legitimate runtime use cases for dynamic <style> elements #197

Description

@zsviczian

I agree with the general guidance behind discouraging dynamically attached <style> elements. Static styles.css, classes, setCssProps(), and setCssStyles() should be preferred whenever they are equivalent.

This came up while auditing native DOM creation in #196. I reviewed all 20 related lint findings in Excalidraw and was able to remove 8 using the APIs recommended there. The remaining 12 all create <style> elements; 5 are iframe-specific and remain under #196. This issue is about the separate non-iframe stylesheet case.

setCssProps() / setCssStyles() are not equivalent when the requirement is a stylesheet rather than declarations on a single element. They cannot express selectors, pseudo-elements, at-rules, or arbitrary rule text.

A concrete example is PDF export in Excalidraw Extras. During Electron print-to-PDF, the plugin installs a temporary stylesheet containing:

  • @media print;
  • selectors affecting the temporary print tree;
  • pseudo-elements such as ::-webkit-scrollbar;
  • per-export values such as the requested background color;
  • optional export-specific CSS.

The stylesheet exists only for the print operation and is removed in finally.

Moving these rules to the plugin's static stylesheet is not equivalent because some values and rules are generated for the individual export. Applying inline styles is also not equivalent because it cannot represent selectors, pseudo-elements, or print-specific at-rules.

I propose to keep dynamic <style> elements discouraged by default while providing a clear path for the exceptional cases where a runtime stylesheet is actually the appropriate abstraction.

Possible approaches:

  1. Allow a narrowly scoped, documented exception when static CSS or element-level styling is not semantically equivalent.
  2. Alternatively, document an Obsidian-supported pattern for lifecycle-owned runtime stylesheets that can contain selectors/at-rules and be removed when no longer needed.

Either approach would preserve the value of the rule while giving legitimate runtime stylesheet cases a clear, reviewable resolution path.

Related: obsidianmd/stylelint-config#6 discusses a similar exception question at the CSS declaration level for intentional !important usage.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions