LiveCapture
View Source<img align="right" width="96" height="96"
alt="LiveCapture logo"
src="images/logo-256.svg">Zero-boilerplate storybook for LiveView components
Explore component libraries · Documentation · Hex
Need help with LiveCapture integration or your LiveView project? Hire me
Features
- Render HEEx components with predefined state snapshots
- Quickly test visual quality by switching between different width breakpoints
- Explore component documentation with dynamic state inspection
- Nice DSL with a strong focus on ergonomics and simplicity
Quick start
Add the :live_capture dependency to the mix.exs and .formatter.exs.
mix.exs
{:live_capture, "~> 0.2"}.formatter.exs
[
import_deps: [:live_capture, ...]
]Define a configuration module.
defmodule MyAppWeb.LiveCapture do
use LiveCapture.Component
breakpoints s: "480px", m: "768px", l: "1279px", xl: "1600px"
root_layout {MyAppWeb.LayoutView, :root}
endMount LiveCapture in router.ex.
[!TIP] You can mount multiple configuration modules by passing them as a list instead.
import LiveCapture.Router
scope "/" do
live_capture "/live_capture", MyAppWeb.LiveCapture
endCapture your first component story.
[!TIP] You can place
use MyAppWeb.LiveCapturenext touse Phoenix.Componentinmy_app_web.ex. This makes thecapture/0,capture/1, andcapture_all/0macros available in all component files.
use MyAppWeb.LiveCapture
capture()
def my_component(assigns) do
~H"""
My component
"""
endExplore the main capture patterns in example.ex
Capture patterns
Calling use MyAppWeb.LiveCapture makes three macros available inside your module:
capture/0to simply capture a componentcapture/1to capture a component with attributes and state variantscapture_all/0to automatically capture all HEEx components inside the file
Simple capture with capture/0
If you have a component defined with default attributes, you can render it "as is" with a capture/0 call.
[!TIP] LiveCapture supports two patterns for default attributes:
:defaultand:examples(with:examplestaking priority).
attr :name, :string, default: "Main", examples: ["Primary", "Secondary"]
capture()
def my_component(assigns), do: ~H"My component: {@name}"Set attribute values with capture/1
:attributes key allows you to override any default values defined with attr macro
attr :name, :string, required: true
capture attributes: %{name: "Main"}
def my_component(assigns), do: ~H"My component: {@name}"Multiple variants of the same component
:variants key allows you to define multiple component state snapshots
attr :name, :string, required: true
capture variants: [
main: %{name: "Main"},
secondary: %{name: "Secondary"},
]
def my_component(assigns), do: ~H"My component: {@name}"Components with slots
[!TIP] All
:inner_blockstrings are treated as regular HEEx templates.
slot :header
slot :inner_block, required: true
slot :rows do
attr :name, :string
end
capture attributes: %{
header: "This is header slot",
inner_block: "Content of the inner block {1+2}",
rows: [
%{inner_block: "Slot content", name: "Attribute content"}
]
}
def my_component(assigns), do: ~H"..."Large components with a complex state structure
LiveCapture makes it possible to render live components and capture a visual snapshot of the render/1 function used by LiveView dynamic components.
defmodule MyAppWeb.Profile.ShowLive do
use MyAppWeb, :live_view
use MyAppWeb.LiveCapture
alias MyAppWeb.LiveCaptureFactory
def mount(_, _, socket), do: {:ok, socket}
capture attributes: %{
current_user: LiveCaptureFactory.build(:current_user)
}
def render(assigns) do
~H"""
Example of a large HEEx component with a complex state structure
"""
end
endTo declutter the component code, you can move the definition of complex or recurring state values inside the factory module
defmodule MyAppWeb.LiveCaptureFactory do
alias MyApp.Users
def build(:current_user) do
%Users.User{id: 1, name: "First Last"}
end
endIt's also possible to move the declaration of the whole variant attributes payload inside the factory. You can define and arrange factory modules in a way that fits your project structure best.
defmodule MyAppWeb.LiveCaptureWebFactory do
alias MyAppWeb.Profile
alias MyAppWeb.LiveCaptureFactory
def build(Profile.ShowLive, :main) do
%{
user: LiveCaptureFactory.build(:current_user)
}
end
endComponents with scripts and styles that require CSP nonce attribute
Some components render inline scripts and styles that might require a nonce attribute.
def style_nonce(nonces), do: nonces.csp_style_nonce
def script_nonce(nonces), do: nonces.csp_script_nonce
capture attributes: %{
style_nonce: LiveCapture.Attribute.with_csp_nonces(&__MODULE__.style_nonce/1),
script_nonce: LiveCapture.Attribute.with_csp_nonces(&__MODULE__.script_nonce/1)
}
def my_component(assigns), do: ~H"..."Update live_capture/3 with conn assign keys of CSP nonces.
live_capture "/live_capture",
MyAppWeb.LiveCapture,
csp_nonce_assign_key: %{
style: :style_csp_nonce,
script: :script_csp_nonce
}Root Layouts with custom conn assigns
The plugs option can configure a list of plugs that will be called during the component render.
defmodule MyAppWeb.LiveCapture do
use LiveCapture.Component
plugs [MyAppWeb.CustomPlug, {MyAppWeb.CustomPlugWithConfig, key: "value"}]
endLicense
Copyright (c) 2026 Boris Kuznetsov me@achempion.com
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.