Relaycode

Enum Input

Variant selector for Substrate enum types with dynamic inner value resolution

import { Enum } from "@/components/params/inputs/enum";

<Enum
  name="threshold"
  label="Vote Threshold"
  client={client}
  variants={[
    { name: "SuperMajorityApprove", docs: ["A supermajority of aye votes..."] },
    { name: "SuperMajorityAgainst", docs: ["A supermajority of nay votes..."] },
    { name: "SimpleMajority", docs: ["A simple majority..."] },
  ]}
  onChange={(val) => console.log("Selected:", val)}
/>

Enum Input

The Enum input handles all Substrate enum (variant) types from chain metadata. It presents a dropdown for selecting which variant is active, then dynamically renders the appropriate sub-inputs for that variant's fields. Enums are one of the most common composite types in Substrate -- used for calls, errors, events, and configuration options throughout every pallet.

Supported Types

The Enum component sits at priority 30 in the registry with no explicit type name patterns. Instead, it is resolved through the TypeDef fallback mechanism: when no higher-priority pattern matches and the chain metadata reports the type's TypeDef as "Enum", findComponent returns the Enum component.

This means the Enum component handles any type that the metadata declares as an enum, regardless of its name.

Props

The component extends ParamInputProps with an additional variants prop:

PropTypeRequiredDescription
namestringYesField identifier used for the HTML id and form state
labelstringNoDisplay label shown above the selector
descriptionstringNoHelp text shown below the component
typeNamestringNoThe SCALE type name
isDisabledbooleanNoDisables the selector and all sub-inputs
isRequiredbooleanNoShows a red asterisk next to the label
errorstringNoValidation error message to display
clientDedotClient<PolkadotApi>YesConnected Dedot client for resolving variant types from metadata
typeIdnumberNoMetadata type ID used to look up the enum's variants
valueanyNoExternally controlled value in { type, value? } format
onChange(value: unknown) => voidNoCallback fired with the variant selection
variantsEnumVariant[]NoExplicit variant definitions (overrides metadata resolution)

EnumVariant Interface

interface EnumVariant {
  name: string;
  fields?: { typeId: number; typeName?: string; name?: string }[];
  docs?: string[];
  component?: React.ReactNode;
}

When variants is not provided, the component reads variants directly from the chain metadata using client.registry.findType(typeId).

Features

  • Auto-resolves variants from chain metadata: When connected to a chain, the component reads the enum's member list from the runtime metadata -- no manual variant configuration needed.
  • Unit variants: Variants with no fields (like Staked, None, SimpleMajority) emit immediately on selection with no sub-input.
  • Data variants: Variants with associated data render sub-inputs dynamically using findComponent to resolve the correct component for each field's type.
  • Single-field inline rendering: When a variant has exactly one field, the sub-input renders inline directly below the selector.
  • Multi-field struct-like rendering: When a variant has multiple fields, they render as a group with an indented left border, similar to struct fields.
  • Variant documentation tooltips: If the metadata includes doc strings for a variant, hovering over it in the dropdown shows a tooltip with the documentation.
  • Data indicator: Variants with associated fields show an ellipsis marker in the dropdown to indicate they require additional input.

Type Resolution

import { findComponent } from "@/lib/input-map";

// Enum is resolved via the TypeDef fallback, not by type name patterns.
// When the metadata reports typeId 42 as an Enum:
const resolved = findComponent("SomeCustomEnum", 42, client);
// Returns { component: Enum, schema, typeId: 42 }

Usage

The Enum component is rendered by the extrinsic builder when a parameter's metadata type is an enum. Direct usage:

import { Enum } from "@/components/params/inputs/enum";

<Enum
  name="payee"
  label="Reward Destination"
  client={client}
  typeId={42}
  onChange={(val) => console.log("Selected:", val)}
/>

With explicit variants (bypassing metadata):

<Enum
  name="threshold"
  label="Vote Threshold"
  client={client}
  variants={[
    { name: "SuperMajorityApprove" },
    { name: "SuperMajorityAgainst" },
    { name: "SimpleMajority" },
  ]}
  onChange={(val) => console.log("Selected:", val)}
/>

Validation

The component uses a Zod schema that expects an object with a type string and an optional value:

const schema = z.object({
  type: z.string(),
  value: z.any().optional(),
});

Value Format

The onChange callback receives an object:

// Unit variant (no fields)
{ type: "Staked" }

// Data variant (with inner value)
{ type: "Account", value: "5GrwvaEF..." }

// Complex data variant
{ type: "Split", value: { aye: "1000000", nay: "500000" } }

The type field always contains the variant name as a string. The value field is present only when the selected variant has associated data, and its shape depends on the variant's field types.