ViewComponent/view_component · error · ViewComponent::MissingPreviewTemplateError

A preview template for example EXAMPLE doesn't exist. To fi

Error message

A preview template for example EXAMPLE doesn't exist.

To fix this issue, create a template for the example.

What it means

When a preview example method returns nil (or a hash without a :template key), render_args falls back to looking up a template file at <preview_path>/<preview_name>_preview/<example>.html.* across Base.previews.paths. If no such file exists in any preview path, preview_example_template_path raises ViewComponent::MissingPreviewTemplateError. The fix is either to return a render hash from the example or to provide the template file.

Source

Thrown at lib/view_component/preview.rb:88

      def preview_name
        name.chomp("Preview").underscore
      end

      # rubocop:disable Style/TrivialAccessors
      # Setter for layout name.
      def layout(layout_name)
        @layout = layout_name
      end
      # rubocop:enable Style/TrivialAccessors

      # Returns the relative path (from preview_path) to the preview example template if the template exists
      def preview_example_template_path(example)
        preview_path =
          Array(preview_paths).detect do |path|
            Dir["#{path}/#{preview_name}_preview/#{example}.html.*"].first
          end

        raise MissingPreviewTemplateError.new(example) if preview_path.nil?

        path = Dir["#{preview_path}/#{preview_name}_preview/#{example}.html.*"].first
        Pathname.new(path)
          .relative_path_from(Pathname.new(preview_path))
          .to_s
          .sub(/\..*$/, "")
      end

      # @private
      def __vc_load_previews
        Array(preview_paths).each do |preview_path|
          Dir["#{preview_path}/**/*preview.rb"].sort.each { |file| require file }
        end
      end

      private

      def preview_paths

View on GitHub (pinned to 9f22c36fa7)

Solutions

  1. Make the example method return a render call: def default; render(UserComponent.new); end — then no template file is needed.
  2. Or create the preview template file at <preview_path>/user_preview/default.html.erb (matching preview_name_preview/<example>.html.*).
  3. Verify config: Rails.application.config.view_component.preview_paths actually contains the directory holding the template.
  4. Check the file name matches the example method exactly (default.html.erb for def default).

Example fix

# before
class UserPreview < ViewComponent::Preview
  def default
    # returns nil -> falls back to template lookup -> MissingPreviewTemplateError
  end
end

# after
class UserPreview < ViewComponent::Preview
  def default
    render(UserComponent.new(user: users(:one)))
  end
end
Defensive patterns

Strategy: validation

Validate before calling

example = "default"
has_template = Array(ViewComponent::Base.previews.paths).any? do |p|
  Dir["#{p}/#{UserPreview.preview_name}_preview/#{example}.html.*"].any?
end

raise ArgumentError, "need render(...) or a template file" unless has_template || UserPreview.new.respond_to?(example)

Try / catch

begin
  UserPreview.render_args(example)
rescue ViewComponent::MissingPreviewTemplateError
  render html: "Create previews/#{UserPreview.preview_name}_preview/#{example}.html.erb", status: :not_found
end

Prevention

When it happens

Trigger: A preview example whose body is empty or returns nil (def default; end) with no previews/<name>_preview/<example>.html.erb file; example methods that only set up fixtures and forget render(...); preview_paths (ViewComponent::Base.previews.paths, default test/components/previews) not including the directory where the template lives.

Common situations: Scaffolding a new preview and forgetting either the render call or the template; moving preview templates during a directory restructure so the Dir[] glob no longer matches; setups where previews live in spec/components/previews but only test/components/previews is configured.

Related errors


AI-assisted analysis of ViewComponent/view_component@9f22c36fa7 (2026-08-23). Data as JSON: /api/errors/79bc34a35c21c514. Report an issue: GitHub.