VoidhashDocs
DevelopersHelp centerGuidesAPI reference
Dashboard
Get started
Introduction
Quickstart
How Voidhash works
Glossary
Versions and releases
Concepts
Teams, projects and environments
API keys
Products and perks
Offers
Subscription lifecycle
People and identity
Groups
Events
Features
Paywalls in your app
Feature flags and A/B tests
Paywall components
Push notifications
Ad attribution in your app
Client SDKs
React Native
Swift
Kotlin
Web
Your backend
Node.js
PHP
Go
Rust
Other languages
Payment sources
Forward store notifications
Developer tools
CLI
MCP server
Query analytics with VoidQL
Components
Develop a component
Editor panels
Panel handlers and state
Component definition
Component props
Publishing
Installing and capabilities

Develop a component

Edit your project's components on your computer, see every change in the paywall editor, and publish them as new versions.

A component is a Rust crate built with the voidhash-ui library. voidhash dev keeps a copy of your project's components on your computer, builds them as you edit, and shows each build in the paywall editor within seconds. voidhash publish turns your changes into new versions your paywalls can use.

Before you start

You need stable Rust and its WebAssembly target:

rustup target add wasm32-unknown-unknown

Run the commands on this page in your app's root, next to the voidhash.config.ts that voidhash init created. They act for that project and for you, so sign in with voidhash login; a project's secret key can't run them. To build the CLI, see Install the CLI.

Start the dev loop

voidhash dev

The first time, dev creates a .voidhash directory and adds it to your .gitignore (creating the file when there is none). Then it:

  1. downloads the source of every component of the project. A component that was uploaded as a built module has no source to edit; dev lists it as not editable;
  2. builds each component and its editor panel;
  3. serves the builds to the paywall editor, on your computer only, and rebuilds a component each time you save one of its files.

Keep it running while you work. It listens on port 4319; pass --port <port> when that port is taken.

The working copy

.voidhash is a Cargo workspace. Open it in your editor so Rust tooling such as rust-analyzer sees every component:

PathContents
Cargo.tomlThe workspace. It is yours to change once created.
components/<slug>/One component crate: its Cargo.toml, src/lib.rs and any other modules.
components/<slug>/src/panel.rsThe component's editor panel, when it has one.
state.jsonWhat the CLI knows of each component. Do not edit it.
target/Build output.

A component in .voidhash has the id project/<slug>, after its directory's name. Give the same id in #[component(id = …)] and #[panel(for = …)], as voidhash new does; dev reports a build whose id does not match.

Create a component

voidhash new creates a component with its editor panel in the working copy:

voidhash new badge

It writes .voidhash/components/badge/ with a working component in src/lib.rs and its panel in src/panel.rs. A running dev builds it at once. Until you publish it, only you see it, under Local in the paywall editor.

One crate, two modules

The crate builds twice. The default runtime feature builds the component module that paywalls run in your app. The panel feature builds the editor panel module, which only the paywall editor loads, so panel code never reaches your app.

Cargo.toml
[features]
default = ["runtime"]
runtime = []
panel = ["voidhash-ui/panel"]

Both builds share the crate's types, so the component and its panel agree on its props. A component without an editor panel needs neither feature.

See your builds in the paywall editor

Open any paywall of the project in the editor, signed in as the person who runs dev. There is nothing to link: the editor finds your dev and uses its builds.

  • Every instance of a component you serve draws with your latest build, on the canvas and in the right panel, which shows the build's props, traits and editor panel.
  • Local builds, at the top of the layers panel, says how your builds stand. Select it to see each component, whether it changed since its last version, and the error and build log of a build that failed. The editor keeps showing a component's last good build until you fix the error.
  • Use published versions, in the same place, shows the versions your instances pin instead, without stopping dev. Turn it off to see your builds again.
  • Components you created with voidhash new are listed under Local when you add a component, so you can place them on the canvas.
  • A prop that only your build declares is marked Local build only. You can set it, and the value is saved with the paywall, but the version the instance pins ignores it until you publish a version that declares it.
  • When dev stops, the editor says it cannot reach it, and within half a minute returns to the published versions.

Teammates who open the same paywall see the published versions, and your builds never reach your apps.

Chrome may ask whether the site can reach devices on your local network. Allow it: the editor needs it to reach dev on your computer. If the editor reports a version of dev it does not support, update the CLI or reload the editor, whichever is older.

Changes from the Voidhash agent and teammates

A teammate, or an AI agent connected to the MCP server, can publish a new version of a component while you work. dev checks for new versions every few seconds and merges them into your working copy:

  • Changes to parts of a file you did not change merge quietly. dev says which files it merged.
  • When you and the new version changed the same lines, dev writes both, between conflict markers (<<<<<<< local, =======, >>>>>>> v5), and marks the component as conflicted. Keep what you want, remove the markers, and save. Until then, the component cannot be published.

Publish your changes

voidhash publish compares your working copy with the project and lists each new or changed component with the files that changed:

voidhash publish

Choose the components to publish; a conflicted one can be chosen once you resolve it. Each one becomes a new version: Voidhash builds it from your source and checks it, and the command reports the result of every build, with its log when one fails.

To publish without the prompt, for example from a script, name the components or take them all:

voidhash publish --component badge --yes
voidhash publish --all --yes

Building a paywall that uses your builds

A new component version does not change placed instances: each instance keeps the version it pins. So that a paywall never goes live with something other than what you saw, the editor refuses to build it while:

  • an instance of a component exists only on your computer, or shows a build with changes you have not published: run voidhash publish;
  • an instance pins an older version than the one you published or based your work on: choose Update N instances to vX in the dialog. It moves those instances to the new version in one step, which you can undo, keeping the props the new version still declares.

The dialog lists every blocking component with its fix. Then build and deploy the paywall as usual.

Test

Unit tests run with cargo test in a component's directory. voidhash_ui::testing mounts a component, presses its buttons and records what it asks the paywall to do. voidhash_ui::panel::testing does the same for a panel. See Test a panel.

voidhash test runs the checks publishing runs, on your machine:

voidhash test badge

It builds the component, checks the panel module, then runs the component conformance suite. The suite needs the conformance checker on your PATH, or its location in VOIDHASH_CONFORMANCE. Without it, the command reports that the suite did not run and exits with an error. Pass a crate directory instead of a component's name to test a crate outside .voidhash; the command writes its modules to target/voidhash.

Publishing runs the same checks on the server. A version that fails them is kept, so the Components page and voidhash registry list can show you which checks failed, but it cannot be inserted into a paywall or released. A self-hosted server without a component build service skips the conformance suite and marks each version conformance-not-run.

To test modules you built some other way, pass the component module. The panel module is panel.wasm next to it, or the file you pass with --panel.

A typical loop

voidhash dev                    # keep running while you edit
voidhash new countdown          # in another terminal, when you need a new component
cargo test --manifest-path .voidhash/Cargo.toml
voidhash publish

Then update the instances when the editor asks, and build and deploy the paywall. To share a component with every project of your organization, see Publishing.

Next steps

  • Add an editor panel
  • Share a component with your organization
  • Build and deploy the paywall

Something wrong or missing on this page? Tell us by email or on Discord.

PreviousComponentsNextEditor panels

On this page

Before you startStart the dev loopThe working copyCreate a componentOne crate, two modulesSee your builds in the paywall editorChanges from the Voidhash agent and teammatesPublish your changesBuilding a paywall that uses your buildsTestA typical loopNext steps