The project is in a healthy, maintained state
Captures a safe ViewComponent render tree for a browser DevTools panel.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Runtime

>= 7.1, < 9
>= 2.2, < 4
>= 7.1, < 9
>= 3.0, < 5
 Project Readme

ViewComponent DevTools

Inspect Rails ViewComponent render trees, component state, and render timings directly in your browser's DevTools.

Note

ViewComponent DevTools is in early development and should only be used in trusted development environments.

ViewComponent DevTools inspecting a component tree and its properties

Features

  • Explore nested ViewComponent render trees and render timings.
  • Inspect public component properties and instance variables with conservative normalization and credential redaction.
  • Pick a rendered component from the page and reveal it in the tree without adding wrapper elements to your markup.
  • Search component names with plain text or regular expressions.
  • Navigate the tree by keyboard and move through a component's ancestors.
  • Ignore exact component names or wildcard namespaces such as Primer::*.
  • Target Chromium with Manifest V3, with experimental Firefox packaging.

Packages

This repository contains two packages:

Package Description
packages/view_component_devtools A Rails gem that records the native render.view_component instrumentation tree and exposes a bounded, conservatively redacted JSON payload.
packages/browser-extension A WXT + React browser extension that adds a View Components panel to DevTools and renders the component tree and details.

Requirements

  • Ruby 3.2+
  • Rails 7.1+
  • ViewComponent 3.0-4.x
  • Node 20+
  • pnpm 10+

The project was developed with Ruby 3.4.1 and Node 22.12.0.

Installation

Add the local or published gem to the development bundle only:

# Gemfile
gem "view_component_devtools", group: :development

Exclude development dependencies from production installs, for example with BUNDLE_WITHOUT=development:test. This is the only way to ensure the gem's code is not installed or loaded in production.

Enable capture explicitly when the gem is available:

# config/initializers/view_component_devtools.rb
if defined?(ViewComponentDevtools)
  ViewComponentDevtools.configure do |config|
    config.enabled = true
  end
end

Include the concern in the shared component base. Native events are captured without it, but component properties and page selection require it:

class ApplicationComponent < ViewComponent::Base
  include ViewComponentDevtools::Component if defined?(ViewComponentDevtools::Component)
end

Finally, add the payload helper after the application body so all components rendered by yield have completed:

<body>
  <%= yield %>
  <%= view_component_devtools_payload if respond_to?(:view_component_devtools_payload) %>
</body>

Build the Chromium extension from this repository:

pnpm setup
pnpm build

The extension is written to packages/browser-extension/.output/chrome-mv3. Load that directory from chrome://extensions with Developer mode and Load unpacked. Close and reopen DevTools after installing or reloading the extension.

Usage

Open your Rails application, then open Chrome DevTools and select the View Components tab. It may be under the ยป overflow menu. The toolbar popup only shows usage instructions; the inspector itself lives in DevTools.

Click the element-picker button in the panel toolbar, hover a rendered component, and click to reveal it in the component tree. The picker uses invisible HTML comments emitted by the component concern, so it does not add wrapper elements or affect page layout.

Search component names with plain text or /regular expressions/; use Enter and Shift+Enter to move between matches. The component tree supports arrow-key navigation, and the details pane links back through the selected component's ancestors. Settings can ignore exact component names or wildcard namespace rules such as Primer::*. Use Refresh after a server render that does not trigger a top-level navigation.

Captured properties

Property discovery is local to each concrete component class. Every public instance method declared directly on that class with no parameters is captured, including attr, attr_reader, and the reader half of attr_accessor. Inherited and included methods are excluded, as are methods with required, optional, rest, or keyword parameters. A method that raises is displayed as an error marker without interrupting the component render. Every instance variable present before rendering is also captured under its @-prefixed name, including variables without public readers.

class AvatarComponent < ApplicationComponent
  attr_reader :user, :size

  def initialize(user:, size: 32)
    @user = user
    @size = size
  end

  def size_label
    "#{size}px"
  end
end

user is represented as [unsupported User] rather than serialized. Prefer small scalar readers such as user_id or user_name when useful.

Configuration

Setting Default Purpose
enabled false Explicitly enables development capture.
max_depth 8 Maximum nested property depth.
max_collection_size 50 Maximum array/hash entries.
max_string_length 2_000 Maximum characters per string.
redact_keys credential patterns Additional strings or regular expressions to redact.

See SECURITY.md before changing capture or redaction behavior.

Architecture

sequenceDiagram
  participant VC as ViewComponent
  participant AS as ActiveSupport::Notifications
  participant Gem as DevTools gem
  participant Page as Rails layout
  participant Panel as Browser DevTools panel

  VC->>AS: render.view_component start/finish
  Gem->>AS: evented subscription
  Gem->>Gem: request-local tree + safe property normalization
  Page->>Gem: view_component_devtools_payload
  Gem-->>Page: application/json script element
  Panel->>Page: inspectedWindow.eval(read textContent)
  Page-->>Panel: JSON string
Loading

The evented ActiveSupport subscriber preserves nested render order without patching ViewComponent. An optional concern wraps the public render_in method only to associate a component instance with its native event. It captures values from direct public methods and current instance variables. State uses ActiveSupport::IsolatedExecutionState, is created by Rack middleware per request, and is cleared when the response body closes or immediately when the application raises.

The extension uses WXT so the same source can target Chromium and Firefox. The MVP is validated against Manifest V3 Chromium output; Firefox packaging is available as an experimental build target.

Development

Install dependencies, run the complete test suite, and build the extension:

pnpm setup
pnpm test
pnpm build

To produce an experimental Firefox build, run:

pnpm build:firefox

Demo

The executable fixture uses the gem's real subscriber, request state, normalizer, concern, and payload helper:

BUNDLE_GEMFILE=packages/view_component_devtools/Gemfile bundle exec \
  ruby examples/generate_demo.rb > tmp/view_component_devtools_demo.html
ruby -run -e httpd tmp -p 4000

Visit http://localhost:4000/view_component_devtools_demo.html, open DevTools, and select View Components. The tree contains Demo::PageComponent with a nested Demo::CardComponent; the card token is redacted. This fixture proves the same page contract used by Rails without requiring a generated Rails application in the repository.

Limitations and roadmap

  1. Components captured only through native instrumentation appear in the tree, but are not selectable on the page unless they include the component concern.
  2. Streaming responses must keep their Rack body open until iteration finishes; this is already how compliant Rack servers behave, but dedicated streaming coverage is future work.
  3. The panel displays one payload per inspected document and does not yet retain render history or Turbo frame snapshots.
  4. Next steps are DOM/source highlighting, Turbo navigation integration, richer slot metadata, Firefox validation/signing, and a generated Rails demo application.

Security

ViewComponent DevTools can expose application internals and is intentionally disabled by default. Keep it out of production bundles and read SECURITY.md for the complete capture, redaction, and reporting guidance.

Contributing

Issues and pull requests are welcome. Run pnpm test before submitting a change. Changes to capture or redaction behavior should include focused gem tests and account for the guarantees documented in SECURITY.md.

License

ViewComponent DevTools is available under the MIT License.