This documentation covers the input components used in the Relaycode extrinsic builder. Each component handles a specific Substrate type and provides appropriate UI controls for user input.
All input components live in components/params/inputs/ and share a common interface:
components/params/
├── types.ts # ParamInputProps interface
└── inputs/
├── account.tsx # SS58 address input
├── amount.tsx # Integer numeric input
├── balance.tsx # Token amount with denominations
├── boolean.tsx # Boolean toggle
├── btree-map.tsx # BTreeMap key-value pairs
├── btree-set.tsx # BTreeSet unique values
├── bytes.tsx # Hex byte array
├── call.tsx # Nested extrinsic builder
├── enum.tsx # Variant selector
├── hash.tsx # H160/H256/H512 input
├── key-value.tsx # Key-value pair
├── moment.tsx # Timestamp input
├── option.tsx # Optional value wrapper
├── struct.tsx # Composite type container
├── text.tsx # String/fallback input
├── tuple.tsx # Positional collection
├── vector.tsx # Dynamic array
├── vector-fixed.tsx # Fixed-length array
├── vote.tsx # Vote input
└── vote-threshold.tsx # Vote threshold input
All input components implement this common interface:
interface ParamInputProps {
name: string; // Field identifier
label?: string; // Display label
description?: string; // Help text
typeName?: string; // Substrate type name (e.g., "Balance", "AccountId")
isDisabled?: boolean; // Disable input
isRequired?: boolean; // Show required indicator
error?: string; // Error message to display
client: DedotClient<PolkadotApi>; // Dedot client for type resolution
typeId?: number; // Type ID for complex type resolution
onChange?: (value: unknown) => void; // Value change callback
}Each component exports a Zod validation schema:
// Example from amount.tsx
import { z } from "zod";
const schema = z.string().refine(
(val) => !isNaN(Number(val)) && Number(val) >= 0,
{ message: "Must be a non-negative number" }
);
export function Amount({ ... }) { ... }
Amount.schema = schema;- AccountInput - SS58 addresses
- AmountInput - Integers
- BalanceInput - Token amounts
- BoolInput - Booleans
- TextInput - Strings
- BytesInput - Byte arrays
- HashInput - Fixed-size hashes (H160, H256, H512)
- VectorInput - Dynamic arrays (
Vec<T>) - VectorFixedInput - Fixed-length arrays (
[T; N]) - BTreeMapInput - Key-value maps (
BTreeMap<K, V>) - BTreeSetInput - Unique value sets (
BTreeSet<T>)
- StructInput - Named field objects
- TupleInput - Positional arrays
- OptionInput - Optional values
- EnumInput - Variant types
- CallInput - Nested extrinsics
Components are resolved from type names using the Input Map API:
import { findComponent } from "@/lib/input-map";
// Find component for a Balance type
const { component: BalanceComponent } = findComponent("Balance");
// Find component with typeId for nested resolution
const { component: VecComponent } = findComponent("Vec<AccountId>", typeId);User Input → Component onChange() → Parent Form State → Encoding
↓
Decoding → Parent Form State → Component value prop → Display
Components call onChange with the appropriate value type:
| Component | onChange Value Type |
|---|---|
| Account | string (SS58 address) |
| Amount | string (integer as string) |
| Balance | string (planck value as string) |
| Boolean | boolean |
| BTreeMap | [unknown, unknown][] (array of key-value tuples) |
| BTreeSet | unknown[] (array of unique values) |
| Bytes | string (hex with 0x) |
| Hash | string (hex with 0x) |
| Text | string |
| Option | undefined or inner value |
| Vector | unknown[] |
| VectorFixed | unknown[] (fixed-length array) |
| Struct | Record<string, unknown> |
| Tuple | unknown[] |
| Enum | { type: string; value?: unknown } |
| Call | { type: string; value: { type: string; ...args } } |
Input components are built on shadcn/ui primitives:
Input- Text fieldsSelect- DropdownsSwitch- TogglesButton- ActionsCard- ContainersLabel- Field labelsFormDescription- Help text
Components use several custom hooks:
Address formatting with chain-specific prefix:
const { ss58Prefix, formatAddress, isValidAddress, truncateAddress } = useSS58(client);Token symbol and denominations:
const { symbol, decimals, denominations, existentialDeposit } = useChainToken(client);Recently used address history:
const { recentAddresses, addRecent } = useRecentAddresses();Wallet integration (safe fallbacks when wallet not connected):
const { accounts } = useSafeAccounts();
const { transferable, formattedTransferable } = useSafeBalance({ address });- Input Components Reference - Detailed documentation for each component
- Input Map API - Type resolution system
- Validation API - Input validation utilities