How to enforce a quote style on HTML attributes in an ERB file using erb-lint

Last Updated -

erb-lint is a popular linter for ERB files. It comes with a set of great lint rules built-in, and it's extensible.

However, one thing it lacks is the ability to enforce a particular quote style on your HTML attributes.

Note: We are not talking about the quote style used in the Ruby code embedded in ERB. For those, you can already configure erb-lint with RuboCop, and it will read your RuboCop rules and enforce the quote style for the Ruby code inside your ERB file.

Coming soon: The only Rails UI library you'll ever need

  • Includes a lot of components necessary to build a modern app
  • Dark mode support out of the box ยท Simple to customize & extend
  • Simple primitives as well as complex components - not "another UI library"
  • Patterns I've found incredibly useful over the past years working with Rails

Subscribe now to receive updates and a free preview

To enforce a particular style on HTML attributes, we just need to add a simple custom linter:

First, define your custom linter in .erb-linters/quotes_in_html_attributes.rb:

module ERBLint
  module Linters
    class QuotesInHtmlAttributes < Linter
      include LinterRegistry

      class ConfigSchema < LinterConfig
        property :enforced_quote_style, converts: :to_sym, accepts: [:single, :double], default: :double
      end
      self.config_schema = ConfigSchema


      def run(processed_source)
        parser = processed_source.parser
        parser.nodes_with_type(:tag).each do |tag_node|
          tag = BetterHtml::Tree::Tag.from_node(tag_node)
          next if tag.closing?

          tag.attributes.each do |attribute|
            quote = attribute.value_node&.children&.first
            next unless quote&.type == :quote

            # Quote is a BetterHtml::AST::Node at this point = s(:quote, "'")
            quote = quote.children.first

            # Quote is now either ' || "
            quote_style = quote == "'" ? :single : :double
            next if quote_style == @config.enforced_quote_style

            add_offense(
              attribute.value_node.loc,
              "Use #{@config.enforced_quote_style} quotes for HTML attributes",
              nil,
              :convention
            )
          end
        end
      end

      def autocorrect(_processed_source, offense)
        lambda do |corrector|
          new_quote = @config.enforced_quote_style == :single ? "'" : '"'
          new_source = offense.source_range.source.gsub(/^\s*['"]/, new_quote).gsub(/['"]\s*$/, new_quote)
          corrector.replace(offense.source_range, new_source)
        end
      end
    end
  end
end

Then, enable this linter in your .erb-lint.yml:

---
...
...
linters:
  QuotesInHtmlAttributes:
    enforced_quote_style: double
    enabled: true
...
...

If you prefer single quotes, simply use enforced_quote_style: single in your configuration.

This custom linter is capable of linting erb-lint filename.html.erb as well as auto-correcting erb-lint -a filename.html.erb.

Get more articles like this

Subscribe to my newsletter to get my latest blog posts, and other freebies like Treact, as soon as they get published !