diff --git a/app/docs/[[...slug]]/page.tsx b/app/docs/[[...slug]]/page.tsx
index 0fdd824..ddfa878 100644
--- a/app/docs/[[...slug]]/page.tsx
+++ b/app/docs/[[...slug]]/page.tsx
@@ -26,6 +26,15 @@ import {
ReferendumSelectorDemo,
TrackSelectorDemo,
BountySelectorDemo,
+ MomentDemo,
+ VoteThresholdDemo,
+ KeyValueDemo,
+ VectorFixedDemo,
+ BTreeMapDemo,
+ StructDemo,
+ TupleDemo,
+ VoteDemo,
+ CallDemo,
} from "@/components/docs/demos";
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
@@ -64,6 +73,15 @@ export default async function Page(props: {
ReferendumSelectorDemo,
TrackSelectorDemo,
BountySelectorDemo,
+ MomentDemo,
+ VoteThresholdDemo,
+ KeyValueDemo,
+ VectorFixedDemo,
+ BTreeMapDemo,
+ StructDemo,
+ TupleDemo,
+ VoteDemo,
+ CallDemo,
Tab,
Tabs,
}}
diff --git a/components/docs/demos/advanced-demos.tsx b/components/docs/demos/advanced-demos.tsx
new file mode 100644
index 0000000..2e63f66
--- /dev/null
+++ b/components/docs/demos/advanced-demos.tsx
@@ -0,0 +1,190 @@
+"use client";
+
+import React from "react";
+import { VectorFixed } from "@/components/params/inputs/vector-fixed";
+import { BTreeMap } from "@/components/params/inputs/btree-map";
+import { Struct } from "@/components/params/inputs/struct";
+import { Text } from "@/components/params/inputs/text";
+import { Boolean } from "@/components/params/inputs/boolean";
+import { Vote } from "@/components/params/inputs/vote";
+import { Amount } from "@/components/params/inputs/amount";
+import { Card, CardContent } from "@/components/ui/card";
+import { Label } from "@/components/ui/label";
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@/components/ui/select";
+import Link from "next/link";
+
+export function VectorFixedDemo() {
+ return (
+
+ {}}
+ />
+
+ );
+}
+
+export function BTreeMapDemo() {
+ return (
+
+ {}}
+ />
+
+ );
+}
+
+export function StructDemo() {
+ return (
+
+ {}}
+ fields={[
+ {
+ name: "display",
+ label: "Display Name",
+ typeName: "Text",
+ component: (
+ {}}
+ />
+ ),
+ required: true,
+ },
+ {
+ name: "email",
+ label: "Email",
+ typeName: "Text",
+ component: (
+ {}}
+ />
+ ),
+ },
+ {
+ name: "verified",
+ label: "Verified",
+ typeName: "bool",
+ component: (
+ {}}
+ />
+ ),
+ },
+ ]}
+ />
+
+ );
+}
+
+export function TupleDemo() {
+ const [values, setValues] = React.useState<[string, string]>(["", ""]);
+
+ return (
+
+
+
+
+ setValues((prev) => [v as string, prev[1]])}
+ />
+ setValues((prev) => [prev[0], v as string])}
+ />
+
+
+
+ Simulated tuple layout. The actual Tuple component resolves field types from chain metadata.
+
+
+ );
+}
+
+export function VoteDemo() {
+ return (
+
+ {}}
+ />
+
+ );
+}
+
+export function CallDemo() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The Call input requires a chain connection to populate pallets and methods.{" "}
+
+ Visit the Builder
+ {" "}
+ to try it live.
+
+
+
+
+
+ );
+}
diff --git a/components/docs/demos/index.ts b/components/docs/demos/index.ts
index 640eb20..3f41335 100644
--- a/components/docs/demos/index.ts
+++ b/components/docs/demos/index.ts
@@ -1,8 +1,9 @@
export { AccountDemo } from "./account-demo";
export { BalanceDemo } from "./balance-demo";
export { EnumDemo } from "./enum-demo";
-export { BoolDemo, TextDemo, HashDemo, BytesDemo, AmountDemo } from "./simple-demos";
+export { BoolDemo, TextDemo, HashDemo, BytesDemo, AmountDemo, MomentDemo, VoteThresholdDemo, KeyValueDemo } from "./simple-demos";
export { OptionDemo, VectorDemo } from "./composite-demos";
+export { VectorFixedDemo, BTreeMapDemo, StructDemo, TupleDemo, VoteDemo, CallDemo } from "./advanced-demos";
export {
ValidatorSelectorDemo,
ValidatorMultiSelectorDemo,
diff --git a/components/docs/demos/simple-demos.tsx b/components/docs/demos/simple-demos.tsx
index 3a2963f..0931aaa 100644
--- a/components/docs/demos/simple-demos.tsx
+++ b/components/docs/demos/simple-demos.tsx
@@ -1,20 +1,26 @@
"use client";
-import React from "react";
+import React, { useState } from "react";
import { Boolean } from "@/components/params/inputs/boolean";
import { Text } from "@/components/params/inputs/text";
import { Hash256 } from "@/components/params/inputs/hash";
import { Bytes } from "@/components/params/inputs/bytes";
import { Amount } from "@/components/params/inputs/amount";
+import { Moment } from "@/components/params/inputs/moment";
+import { VoteThreshold } from "@/components/params/inputs/vote-threshold";
+import { KeyValue } from "@/components/params/inputs/key-value";
export function BoolDemo() {
+ const [value, setValue] = useState(false);
+
return (
{}}
+ onChange={(v) => setValue(v as boolean)}
/>
);
@@ -72,3 +78,42 @@ export function AmountDemo() {
);
}
+
+export function MomentDemo() {
+ return (
+
+ {}}
+ />
+
+ );
+}
+
+export function VoteThresholdDemo() {
+ return (
+
+ {}}
+ />
+
+ );
+}
+
+export function KeyValueDemo() {
+ return (
+
+ {}}
+ />
+
+ );
+}
diff --git a/content/docs/api/input-map.mdx b/content/docs/api/input-map.mdx
index 397051d..a73d02d 100644
--- a/content/docs/api/input-map.mdx
+++ b/content/docs/api/input-map.mdx
@@ -54,28 +54,28 @@ The system uses a priority-based registry to match types. Higher priority patter
| Priority | Component | Patterns |
|----------|-----------|----------|
-| 100 | Account | `AccountId`, `AccountId32`, `AccountId20`, `MultiAddress`, `Address`, `LookupSource`, `/^AccountId/`, `/^MultiAddress/` |
-| 95 | Balance | `Balance`, `BalanceOf`, `Compact`, `Compact`, `/^Balance/` |
-| 90 | Amount | `Compact`, `Compact`, `u128`, `u64`, `u32`, `u16`, `u8`, `i128`, `i64`, `i32`, `i16`, `i8`, `/Compact` |
-| 85 | Boolean | `bool` |
-| 82 | Hash160 | `H160`, `/^H160$/` |
-| 80 | Hash256 | `H256`, `Hash`, `/H256/`, `/Hash/` |
-| 78 | Hash512 | `H512`, `/^H512$/` |
-| 75 | Bytes | `Bytes`, `Vec`, `/Bytes/` |
-| 70 | Call | `Call`, `RuntimeCall`, `/Call$/`, `/RuntimeCall>/` |
-| 65 | Moment | `Moment`, `/Moment/` |
-| 60 | Vote | `Vote`, `/^Vote$/` |
-| 55 | VoteThreshold | `VoteThreshold`, `/VoteThreshold/` |
-| 50 | KeyValue | `KeyValue`, `/KeyValue/` |
-| 45 | Option | `/^Option` |
-| 43 | VectorFixed | `/^\[.+;\s*\d+\]$/` (e.g., `[u8; 32]`) |
-| 42 | BTreeMap | `/^BTreeMap` |
-| 41 | BTreeSet | `/^BTreeSet` |
-| 40 | Vector | `/^Vec`, `/^BoundedVec` |
-| 38 | Tuple | `/^\(/`, `/^Tuple/` |
-| 35 | Struct | (no patterns - fallback for composite types) |
-| 30 | Enum | (no patterns - fallback for enum types) |
-| — | Text | (default fallback for unknown types) |
+| 100 | [Account](/docs/components/account-input) | `AccountId`, `AccountId32`, `AccountId20`, `MultiAddress`, `Address`, `LookupSource`, `/^AccountId/`, `/^MultiAddress/` |
+| 95 | [Balance](/docs/components/balance-input) | `Balance`, `BalanceOf`, `Compact`, `Compact`, `/^Balance/` |
+| 90 | [Amount](/docs/components/amount-input) | `Compact`, `Compact`, `u128`, `u64`, `u32`, `u16`, `u8`, `i128`, `i64`, `i32`, `i16`, `i8`, `/Compact` |
+| 85 | [Boolean](/docs/components/bool-input) | `bool` |
+| 82 | [Hash160](/docs/components/hash-input) | `H160`, `/^H160$/` |
+| 80 | [Hash256](/docs/components/hash-input) | `H256`, `Hash`, `/H256/`, `/Hash/` |
+| 78 | [Hash512](/docs/components/hash-input) | `H512`, `/^H512$/` |
+| 75 | [Bytes](/docs/components/bytes-input) | `Bytes`, `Vec`, `/Bytes/` |
+| 70 | [Call](/docs/components/call-input) | `Call`, `RuntimeCall`, `/Call$/`, `/RuntimeCall>/` |
+| 65 | [Moment](/docs/components/moment-input) | `Moment`, `/Moment/` |
+| 60 | [Vote](/docs/components/vote-input) | `Vote`, `/^Vote$/` |
+| 55 | [VoteThreshold](/docs/components/vote-threshold-input) | `VoteThreshold`, `/VoteThreshold/` |
+| 50 | [KeyValue](/docs/components/key-value-input) | `KeyValue`, `/KeyValue/` |
+| 45 | [Option](/docs/components/option-input) | `/^Option` |
+| 43 | [VectorFixed](/docs/components/vector-fixed-input) | `/^\[.+;\s*\d+\]$/` (e.g., `[u8; 32]`) |
+| 42 | [BTreeMap](/docs/components/btree-map-input) | `/^BTreeMap` |
+| 41 | [BTreeSet](/docs/components/vector-input) | `/^BTreeSet` |
+| 40 | [Vector](/docs/components/vector-input) | `/^Vec`, `/^BoundedVec` |
+| 38 | [Tuple](/docs/components/tuple-input) | `/^\(/`, `/^Tuple/` |
+| 35 | [Struct](/docs/components/struct-input) | (no patterns - fallback for composite types) |
+| 30 | [Enum](/docs/components/enum-input) | (no patterns - fallback for enum types) |
+| — | [Text](/docs/components/text-input) | (default fallback for unknown types) |
### Pattern Matching
@@ -239,23 +239,23 @@ Common Substrate type patterns and their expected components:
| Type | Component | Notes |
|------|-----------|-------|
-| `AccountId`, `AccountId32` | Account | SS58 address input |
-| `MultiAddress` | Account | Supports Id, Index, Raw variants |
-| `Balance`, `BalanceOf` | Balance | With denomination selector |
-| `Compact`, `Compact` | Balance | Compact-wrapped balances get denomination support |
-| `Compact` | Amount | Integer input |
-| `u32`, `u64`, `u128` | Amount | Unsigned integers |
-| `bool` | Boolean | Toggle switch |
-| `H160` | Hash160 | 20-byte hex input |
-| `H256`, `BlockHash` | Hash256 | 32-byte hex input |
-| `H512` | Hash512 | 64-byte hex input |
-| `Vec`, `Bytes` | Bytes | Hex byte array |
-| `[T; N]` | VectorFixed | Fixed-length array (e.g., `[u8; 32]`) |
-| `BTreeMap` | BTreeMap | Key-value pair list |
-| `BTreeSet` | BTreeSet | Unique value set |
-| `Vec` | Vector | Dynamic array |
-| `Option` | Option | Optional with toggle |
-| `(T1, T2, ...)` | Tuple | Positional elements |
-| `{ field: T }` | Struct | Named fields |
-| `enum { A, B }` | Enum | Variant selector |
-| `Call`, `RuntimeCall` | Call | Nested extrinsic |
+| `AccountId`, `AccountId32` | [Account](/docs/components/account-input) | SS58 address input |
+| `MultiAddress` | [Account](/docs/components/account-input) | Supports Id, Index, Raw variants |
+| `Balance`, `BalanceOf` | [Balance](/docs/components/balance-input) | With denomination selector |
+| `Compact`, `Compact` | [Balance](/docs/components/balance-input) | Compact-wrapped balances get denomination support |
+| `Compact` | [Amount](/docs/components/amount-input) | Integer input |
+| `u32`, `u64`, `u128` | [Amount](/docs/components/amount-input) | Unsigned integers |
+| `bool` | [Boolean](/docs/components/bool-input) | Toggle switch |
+| `H160` | [Hash160](/docs/components/hash-input) | 20-byte hex input |
+| `H256`, `BlockHash` | [Hash256](/docs/components/hash-input) | 32-byte hex input |
+| `H512` | [Hash512](/docs/components/hash-input) | 64-byte hex input |
+| `Vec`, `Bytes` | [Bytes](/docs/components/bytes-input) | Hex byte array |
+| `[T; N]` | [VectorFixed](/docs/components/vector-fixed-input) | Fixed-length array (e.g., `[u8; 32]`) |
+| `BTreeMap` | [BTreeMap](/docs/components/btree-map-input) | Key-value pair list |
+| `BTreeSet` | [BTreeSet](/docs/components/vector-input) | Unique value set |
+| `Vec` | [Vector](/docs/components/vector-input) | Dynamic array |
+| `Option` | [Option](/docs/components/option-input) | Optional with toggle |
+| `(T1, T2, ...)` | [Tuple](/docs/components/tuple-input) | Positional elements |
+| `{ field: T }` | [Struct](/docs/components/struct-input) | Named fields |
+| `enum { A, B }` | [Enum](/docs/components/enum-input) | Variant selector |
+| `Call`, `RuntimeCall` | [Call](/docs/components/call-input) | Nested extrinsic |
diff --git a/content/docs/components/btree-map-input.mdx b/content/docs/components/btree-map-input.mdx
index 2f1213d..9fb4913 100644
--- a/content/docs/components/btree-map-input.mdx
+++ b/content/docs/components/btree-map-input.mdx
@@ -3,6 +3,28 @@ title: BTreeMap Input
description: Key-value pair editor for Substrate BTreeMap types with JSON bulk entry
---
+
+
+
+
+
+
+
+```tsx
+import { BTreeMap } from "@/components/params/inputs/btree-map";
+
+ console.log("Map:", val)}
+/>
+```
+
+
+
# BTreeMap Input
The BTreeMap input handles Substrate `BTreeMap` types by rendering a list of key-value pair editors. Each pair has its key and value types resolved from the chain metadata and rendered with the appropriate sub-input components. It supports both form mode for individual pair editing and a JSON mode for bulk entry. BTreeMaps appear in Substrate for configuration maps, storage deposits, and any parameter that expects an ordered key-value collection.
diff --git a/content/docs/components/call-input.mdx b/content/docs/components/call-input.mdx
index 1d0a586..3c2bae9 100644
--- a/content/docs/components/call-input.mdx
+++ b/content/docs/components/call-input.mdx
@@ -3,6 +3,27 @@ title: Call Input
description: Nested extrinsic call builder for Substrate RuntimeCall parameters
---
+
+
+
+
+
+
+
+```tsx
+import { Call } from "@/components/params/inputs/call";
+
+ console.log("Call:", val)}
+/>
+```
+
+
+
# Call Input
The Call input provides a nested extrinsic call builder for parameters that expect a `RuntimeCall` value. It presents pallet and method selectors followed by dynamic parameter inputs, effectively embedding a mini extrinsic builder inside a parameter field. Call inputs appear in Substrate for utility batch calls, proxy executions, multisig approvals, scheduler dispatches, and any extrinsic that wraps another call.
diff --git a/content/docs/components/index.mdx b/content/docs/components/index.mdx
index 6192a48..b55f3b5 100644
--- a/content/docs/components/index.mdx
+++ b/content/docs/components/index.mdx
@@ -1,27 +1,13 @@
---
-title: Components
+title: Overview
description: Substrate-aware input components for the Polkadot ecosystem
---
-# Component Library
+# Component Overview
Relaycode ships a library of **22 input components** and **10 contextual selectors** that map directly to Substrate runtime types. Each component understands the SCALE type it represents, validates input accordingly, and emits values ready for SCALE encoding.
-## Type Resolution
-
-Components are resolved automatically from chain metadata through a **priority-based registry**. When the extrinsic builder encounters a parameter, the `findComponent` function walks the registry from highest to lowest priority, matching the parameter's type name against registered string literals and regular expressions.
-
-```ts
-import { findComponent } from "@/lib/input-map";
-
-// Returns { component: Account, schema, typeId }
-const resolved = findComponent("AccountId32", typeId, client);
-
-// Returns { component: Balance, schema, typeId }
-const resolved = findComponent("Compact", typeId, client);
-```
-
-If no pattern matches, the system falls back to metadata introspection: it reads the `TypeDef` from the chain registry and routes `Enum` types to `EnumInput` and `Struct` types to `StructInput`. Any remaining unknown type falls back to a plain `TextInput`.
+Components are resolved automatically through a [priority-based type resolution system](/docs/api/input-map#type-resolution).
## Available Components
@@ -47,33 +33,7 @@ If no pattern matches, the system falls back to metadata introspection: it reads
| [VoteThresholdInput](/docs/components/vote-threshold-input) | `VoteThreshold` | Threshold selector (SuperMajorityApprove/Against/SimpleMajority) |
| [KeyValueInput](/docs/components/key-value-input) | `KeyValue` | Single key-value pair input |
-## Priority System
-
-The registry assigns each component a numeric priority. When a type name matches multiple patterns, the highest-priority component wins. This prevents ambiguity -- for example, `Compact` (priority 95) is caught by the Balance component before the generic Amount component's `Compact<` regex (priority 90).
-
-| Priority | Component |
-|---|---|
-| 100 | AccountInput |
-| 95 | BalanceInput |
-| 90 | AmountInput |
-| 85 | BoolInput |
-| 82 | HashInput (H160) |
-| 80 | HashInput (H256) |
-| 78 | HashInput (H512) |
-| 75 | BytesInput |
-| 70 | CallInput |
-| 65 | MomentInput |
-| 60 | VoteInput |
-| 55 | VoteThresholdInput |
-| 50 | KeyValueInput |
-| 45 | OptionInput |
-| 43 | VectorFixedInput |
-| 42 | BTreeMapInput |
-| 41 | BTreeSetInput |
-| 40 | VectorInput |
-| 38 | TupleInput |
-| 35 | StructInput |
-| 30 | EnumInput |
+For the full priority ordering and pattern matching details, see the [Input Map API reference](/docs/api/input-map#priority-order).
## Shared Props
diff --git a/content/docs/components/key-value-input.mdx b/content/docs/components/key-value-input.mdx
index bfea96f..2147917 100644
--- a/content/docs/components/key-value-input.mdx
+++ b/content/docs/components/key-value-input.mdx
@@ -3,6 +3,29 @@ title: KeyValue Input
description: Two-field key/value pair input with automatic type resolution
---
+
+
+
+
+
+
+
+```tsx
+import { KeyValue } from "@/components/params/inputs/key-value";
+
+ console.log("Key-Value:", pair)}
+/>
+```
+
+
+
# KeyValue Input
The KeyValue input renders a side-by-side key and value pair within a card. It resolves the types of both fields from chain metadata when available, falling back to plain text inputs. This component is used for `KeyValue` storage items and similar two-field structures.
diff --git a/content/docs/components/moment-input.mdx b/content/docs/components/moment-input.mdx
index f991658..f076548 100644
--- a/content/docs/components/moment-input.mdx
+++ b/content/docs/components/moment-input.mdx
@@ -3,6 +3,29 @@ title: Moment Input
description: Date-time picker with quick presets for timestamp parameters
---
+
+
+
+
+
+
+
+```tsx
+import { Moment } from "@/components/params/inputs/moment";
+
+ console.log("Timestamp:", timestamp)}
+/>
+```
+
+
+
# Moment Input
The Moment input provides a date-time picker for Substrate `Moment` parameters. It uses the browser's native `datetime-local` input and offers quick preset buttons for common time offsets. The selected date-time is converted to a Unix timestamp in milliseconds.
diff --git a/content/docs/components/struct-input.mdx b/content/docs/components/struct-input.mdx
index f4a161e..28b8885 100644
--- a/content/docs/components/struct-input.mdx
+++ b/content/docs/components/struct-input.mdx
@@ -3,6 +3,42 @@ title: Struct Input
description: Composite field group for Substrate struct types with per-field validation
---
+
+
+
+
+
+
+
+```tsx
+import { Struct } from "@/components/params/inputs/struct";
+
+,
+ required: true,
+ },
+ {
+ name: "email",
+ label: "Email",
+ typeName: "Data",
+ component: ,
+ },
+ ]}
+ onChange={(val) => console.log("Struct:", val)}
+/>
+```
+
+
+
# Struct Input
The Struct input renders a group of named fields inside a card, where each field has its own resolved sub-input component. Structs are Substrate's equivalent of named record types -- they appear in extrinsic parameters for multi-field configurations like `IdentityInfo`, `ProxyDefinition`, and any call argument that the metadata defines as a `Struct` TypeDef.
diff --git a/content/docs/components/tuple-input.mdx b/content/docs/components/tuple-input.mdx
index 093fed1..26f2aad 100644
--- a/content/docs/components/tuple-input.mdx
+++ b/content/docs/components/tuple-input.mdx
@@ -3,6 +3,27 @@ title: Tuple Input
description: Positional element group for Substrate tuple types with auto-resolved sub-inputs
---
+
+
+
+
+
+
+
+```tsx
+import { Tuple } from "@/components/params/inputs/tuple";
+
+ console.log("Tuple:", val)}
+/>
+```
+
+
+
# Tuple Input
The Tuple input handles Substrate tuple types by rendering a fixed-length group of positional sub-inputs inside a card. Each element's type is resolved from the chain metadata and rendered with the appropriate component. Tuples appear in Substrate when a parameter combines multiple values without named fields -- for example `(AccountId, Balance)` or `(u32, u32)`.
diff --git a/content/docs/components/vector-fixed-input.mdx b/content/docs/components/vector-fixed-input.mdx
index 6fbbeeb..58ce542 100644
--- a/content/docs/components/vector-fixed-input.mdx
+++ b/content/docs/components/vector-fixed-input.mdx
@@ -3,6 +3,29 @@ title: VectorFixed Input
description: Fixed-length array input for Substrate [T; N] types with specialized byte array handling
---
+
+
+
+
+
+
+
+```tsx
+import { VectorFixed } from "@/components/params/inputs/vector-fixed";
+
+ console.log("Bytes:", val)}
+/>
+```
+
+
+
# VectorFixed Input
The VectorFixed input handles Substrate fixed-length array types (`[T; N]`) with two rendering strategies: byte arrays (`[u8; N]`) get a specialized hex/base64 text input, while other element types render N individual sub-inputs. Fixed-length arrays appear in Substrate for cryptographic data (signatures, public keys), fixed-size identifiers, and any parameter with a compile-time known length.
diff --git a/content/docs/components/vote-input.mdx b/content/docs/components/vote-input.mdx
index 9637b6d..7380861 100644
--- a/content/docs/components/vote-input.mdx
+++ b/content/docs/components/vote-input.mdx
@@ -3,6 +3,28 @@ title: Vote Input
description: Conviction voting input with Standard, Split, and SplitAbstain modes
---
+
+
+
+
+
+
+
+```tsx
+import { Vote } from "@/components/params/inputs/vote";
+
+ console.log("Vote:", vote)}
+/>
+```
+
+
+
# Vote Input
The Vote input provides a full conviction voting interface for OpenGov referenda. It supports three voting modes -- Standard (single direction with conviction), Split (aye/nay balances), and SplitAbstain (aye/nay/abstain balances). It emits a properly formatted `AccountVote` enum value used by the `ConvictionVoting` pallet.
diff --git a/content/docs/components/vote-threshold-input.mdx b/content/docs/components/vote-threshold-input.mdx
index 611fd1a..1fe11ee 100644
--- a/content/docs/components/vote-threshold-input.mdx
+++ b/content/docs/components/vote-threshold-input.mdx
@@ -3,6 +3,27 @@ title: VoteThreshold Input
description: Dropdown selector for referendum vote threshold types
---
+
+
+
+
+
+
+
+```tsx
+import { VoteThreshold } from "@/components/params/inputs/vote-threshold";
+
+ console.log("Threshold:", threshold)}
+/>
+```
+
+
+
# VoteThreshold Input
The VoteThreshold input provides a dropdown for selecting the vote threshold type used in legacy (pre-OpenGov) referendum mechanics. It presents three options -- SuperMajorityApprove, SuperMajorityAgainst, and SimpleMajority -- as a simple select menu.
diff --git a/content/docs/getting-started.mdx b/content/docs/getting-started.mdx
index fedfeda..37400ed 100644
--- a/content/docs/getting-started.mdx
+++ b/content/docs/getting-started.mdx
@@ -18,15 +18,15 @@ Relaycode is an extrinsic builder for the Polkadot ecosystem. It provides a user
## Prerequisites
-- A Polkadot-compatible wallet (Polkadot.js extension, Talisman, SubWallet, etc.)
+- A Polkadot-compatible wallet ([Polkadot.js extension](https://polkadot.js.org/extension/), [Talisman](https://www.talisman.xyz/), [SubWallet](https://www.subwallet.app/), etc.)
- Some DOT or testnet tokens for transaction fees
## Selecting a Chain
Before connecting, choose which chain to interact with using the **Chain Selector** dropdown in the navbar:
-- **Polkadot** - Mainnet (real DOT)
-- **Kusama** - Canary network (real KSM)
+- **Polkadot** - Mainnet (DOT)
+- **Kusama** - Canary network (KSM)
- **Westend** - Testnet (free test tokens, marked with "testnet" badge)
For your first time, we recommend selecting **Westend** so you can experiment without spending real tokens.
@@ -46,18 +46,7 @@ Once connected, you'll see your account balance and be able to select accounts f
Relaycode uses a dual-pane interface:
-```
-┌─────────────────────────────────┬─────────────────────────────────┐
-│ │ │
-│ FORM PANE │ HEX PANE │
-│ │ │
-│ Human-readable inputs │ SCALE-encoded call data │
-│ - Pallet selector │ - Live hex preview │
-│ - Method selector │ - Editable hex input │
-│ - Parameter inputs │ - Auto-decode on edit │
-│ │ │
-└─────────────────────────────────┴─────────────────────────────────┘
-```
+
**Left Pane (Form):** Select pallets, methods, and fill in parameters using friendly input components.
@@ -113,58 +102,11 @@ This hex represents your complete extrinsic call:
You'll see a success message with the transaction hash once it's included in a block.
-## Input Types Explained
-
-Relaycode provides specialized inputs for different Substrate types:
-
-### Account Input
-For addresses and account IDs:
-- Dropdown with connected accounts
-- Recent address history
-- Paste any valid SS58 address
-- Automatic format validation
-
-### Balance Input
-For token amounts:
-- Human-readable input (e.g., "1.5")
-- Denomination selector (DOT/mDOT/planck)
-- Automatic conversion to planck
-- Available balance display
-- Existential deposit warning
-
-### Amount Input
-For plain integers (u32, u64, u128):
-- Simple numeric input
-- Supports large numbers (BigInt)
-
-### Boolean Input
-For true/false values:
-- Toggle switch
-
-### Hash Input
-For block hashes, extrinsic hashes:
-- H160 (20-byte), H256 (32-byte), H512 (64-byte)
-- Format and length validation
-
-### Vector Input
-For arrays (Vec\):
-- Add/remove items
-- Dynamic length
-
-### Fixed Array Input
-For fixed-length arrays (`[T; N]`):
-- Fixed number of elements — no add/remove
-- Each element uses the appropriate typed input
-
-### BTreeMap Input
-For key-value maps (BTreeMap\):
-- Add/remove key-value pairs
-- Typed inputs for keys and values
-
-### Option Input
-For optional values (Option\):
-- Toggle to enable/disable
-- Inner input when enabled
+## Input Types
+
+Relaycode provides specialized inputs for every Substrate type. Instead of generic text fields, you get purpose-built components: account inputs with wallet integration and identicons, balance inputs with denomination switching, nested call builders for batch transactions, and more.
+
+See the [Component Library](/docs/components) for the full list of 22 input components and 10 contextual selectors.
## Common Extrinsics
diff --git a/content/docs/guide/architecture.mdx b/content/docs/guide/architecture.mdx
index 43a0033..e3d7de9 100644
--- a/content/docs/guide/architecture.mdx
+++ b/content/docs/guide/architecture.mdx
@@ -14,25 +14,17 @@ Relaycode is built on a layered architecture designed to cleanly separate concer
The infrastructure layer handles all blockchain connectivity, client management, and wallet integration.
- **Dedot Client** — Relaycode uses [Dedot](https://github.com/dedotdev/dedot) as its Polkadot client (not the deprecated `@polkadot/api`). Dedot provides type-safe chain interactions via `DedotClient`.
-- **Wallet Connection** — LunoKit handles wallet integration, supporting Polkadot.js extension, Talisman, SubWallet, and other compatible wallets.
-- **Chain Switching** — LunoKit's `useSwitchChain()` hook enables switching between Polkadot, Kusama, Westend, and other supported chains using genesis hash as the chain identifier.
-- **React Context** — Providers expose the Dedot client, wallet state, and chain metadata to the component tree via React Context API.
+- **Wallet Connection** — [LunoKit](https://lunokit.xyz) handles wallet integration, supporting [Polkadot.js extension](https://polkadot.js.org/extension/), [Talisman](https://www.talisman.xyz/), [SubWallet](https://www.subwallet.app/), and other compatible wallets.
+- **Chain Switching** — [LunoKit](https://lunokit.xyz)'s `useSwitchChain()` hook enables switching between Polkadot, Kusama, Westend, and other supported chains using genesis hash as the chain identifier.
+- **React Context** — Providers expose the [Dedot](https://docs.dedot.dev) client, wallet state, and chain metadata to the component tree via React Context API.
### 2. Components Layer
The components layer provides reusable UI building blocks.
-- **Parameter Inputs** (`components/params/inputs/`) — Specialized input components for each Substrate type (Account, Balance, Amount, Hash, Vector, etc.).
+- **Parameter Inputs** — [Specialized input components](/docs/components) for each Substrate type (Account, Balance, Amount, Hash, Vector, etc.).
- **Builder Components** (`components/builder/`) — The extrinsic builder panes, pallet/method selectors, and encoding controls.
-- **Base UI** (`components/ui/`) — shadcn/ui components providing consistent styling and behavior. These are generated via `npx shadcn-ui add ` and should not be modified directly.
-
-### 3. App Layer
-
-The app layer handles routing, page layouts, and top-level composition.
-
-- **Next.js App Router** — Pages live under `app/` using Next.js 14 App Router conventions (`page.tsx`, `layout.tsx`).
-- **Builder Page** (`app/builder/`) — The main extrinsic builder tool.
-- **Marketing Pages** (`app/(marketing)/`) — Landing and informational pages.
+- **Base UI** (`components/ui/`) — [shadcn/ui](https://ui.shadcn.com/) components providing consistent styling and behavior. These are generated via `npx shadcn-ui add ` and should not be modified directly.
## Dedot Client Integration
@@ -44,7 +36,7 @@ Relaycode connects to Substrate chains exclusively through Dedot. The client pro
## Input Component Registry
-The input component registry (`lib/input-map.ts`) uses a priority-based pattern matching system to map Substrate type names to the appropriate React input component.
+The [input component registry](/docs/api/input-map) (`lib/input-map.ts`) uses a priority-based pattern matching system to map Substrate type names to the appropriate React input component.
### How It Works
@@ -65,6 +57,8 @@ Higher priority values are checked first, ensuring more specific types take prec
This ordering ensures that `Compact` matches the Balance component (priority 95) rather than the Amount component's `/Compact` regex (priority 90).
+See the [Component Library](/docs/components) for the complete priority table with all components.
+
## Dual-Pane Builder Interface
The extrinsic builder uses a side-by-side dual-pane layout:
@@ -74,6 +68,8 @@ The extrinsic builder uses a side-by-side dual-pane layout:
Changes in either pane sync to the other in real time, providing bi-directional editing.
+
+
## Encoding/Decoding Flow
The encoding and decoding flow connects the form pane to the hex pane:
diff --git a/mdx-components.tsx b/mdx-components.tsx
index d01b2c3..884c715 100644
--- a/mdx-components.tsx
+++ b/mdx-components.tsx
@@ -12,6 +12,15 @@ import {
AmountDemo,
OptionDemo,
VectorDemo,
+ MomentDemo,
+ VoteThresholdDemo,
+ KeyValueDemo,
+ VectorFixedDemo,
+ BTreeMapDemo,
+ StructDemo,
+ TupleDemo,
+ VoteDemo,
+ CallDemo,
} from "@/components/docs/demos";
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
@@ -29,6 +38,15 @@ export function useMDXComponents(components?: MDXComponents): MDXComponents {
AmountDemo,
OptionDemo,
VectorDemo,
+ MomentDemo,
+ VoteThresholdDemo,
+ KeyValueDemo,
+ VectorFixedDemo,
+ BTreeMapDemo,
+ StructDemo,
+ TupleDemo,
+ VoteDemo,
+ CallDemo,
Tab,
Tabs,
...components,
diff --git a/public/docs/account-input.gif b/public/docs/account-input.gif
new file mode 100644
index 0000000..05eba15
Binary files /dev/null and b/public/docs/account-input.gif differ
diff --git a/public/docs/balance-input.gif b/public/docs/balance-input.gif
new file mode 100644
index 0000000..4f8eb7d
Binary files /dev/null and b/public/docs/balance-input.gif differ
diff --git a/public/docs/batch-call-input.gif b/public/docs/batch-call-input.gif
new file mode 100644
index 0000000..6cf4bb2
Binary files /dev/null and b/public/docs/batch-call-input.gif differ
diff --git a/public/docs/bidirectional-editing.gif b/public/docs/bidirectional-editing.gif
new file mode 100644
index 0000000..3ea7277
Binary files /dev/null and b/public/docs/bidirectional-editing.gif differ
diff --git a/public/docs/bool-input.gif b/public/docs/bool-input.gif
new file mode 100644
index 0000000..2147d8d
Binary files /dev/null and b/public/docs/bool-input.gif differ
diff --git a/public/docs/bounty-selector.gif b/public/docs/bounty-selector.gif
new file mode 100644
index 0000000..7678f2c
Binary files /dev/null and b/public/docs/bounty-selector.gif differ
diff --git a/public/docs/bytes-input.gif b/public/docs/bytes-input.gif
new file mode 100644
index 0000000..7a7baa6
Binary files /dev/null and b/public/docs/bytes-input.gif differ
diff --git a/public/docs/enum-input.gif b/public/docs/enum-input.gif
new file mode 100644
index 0000000..7e158be
Binary files /dev/null and b/public/docs/enum-input.gif differ
diff --git a/public/docs/hash-input.gif b/public/docs/hash-input.gif
new file mode 100644
index 0000000..fc8da33
Binary files /dev/null and b/public/docs/hash-input.gif differ
diff --git a/public/docs/option-input.gif b/public/docs/option-input.gif
new file mode 100644
index 0000000..653e76f
Binary files /dev/null and b/public/docs/option-input.gif differ
diff --git a/public/docs/pool-selector.gif b/public/docs/pool-selector.gif
new file mode 100644
index 0000000..c9b193a
Binary files /dev/null and b/public/docs/pool-selector.gif differ
diff --git a/public/docs/referendum-selector.gif b/public/docs/referendum-selector.gif
new file mode 100644
index 0000000..5bd7581
Binary files /dev/null and b/public/docs/referendum-selector.gif differ
diff --git a/public/docs/transfer-demo.gif b/public/docs/transfer-demo.gif
new file mode 100644
index 0000000..a3cfcf1
Binary files /dev/null and b/public/docs/transfer-demo.gif differ
diff --git a/public/docs/validator-selector.gif b/public/docs/validator-selector.gif
new file mode 100644
index 0000000..0480ace
Binary files /dev/null and b/public/docs/validator-selector.gif differ