Skip to content

feat(renderer): form-level ENS address preview mode (rich vs simple) for TransactionForm #197

Description

@pasevin

Summary

Add a form-level setting so TransactionForm / DynamicFormField can render blockchain-address fields with either:

Mode UX Default when omitted
rich Pattern A: AddressFieldWithResolvedPreview + ResolvedAddressFieldPreviewWithNameResolution + parent useWatch
simple Bare AddressField with inline “Resolved to 0x…” announcer (current behavior) yes (backward compat)

Today fieldRegistry maps blockchain-addressAddressField only. Rich preview exists elsewhere (Address Book AddAliasDialog, basic-react-app demos) but is not available to TransactionForm consumers (ui-builder form preview, exported apps, direct integrators).

Downstream tracking: OpenZeppelin/ui-builder#403 (Phase 2 — builder toggle, export schema, tests).


Motivation

  • Single implementation path in @openzeppelin/ui-renderer keeps builder preview, exported apps, and any TransactionForm consumer aligned
  • Integrators can opt into rich ENS UX without custom field wrappers
  • Omitted setting preserves behavior for existing serialized form schemas

Design principles

Capability-led, not ecosystem-specific. Gate behavior on EcosystemRuntime.nameResolution (resolveName / resolveAddress per NameResolutionCapability in @openzeppelin/ui-types). Do not branch on networkConfig.ecosystem === 'evm'.

When nameResolution is absent, both modes degrade to plain address input (existing useRuntimeNameResolverEMPTY_RESOLVER behavior).


Proposed API

@openzeppelin/ui-types

export type EnsAddressPreviewMode = 'rich' | 'simple';

// On CommonFormProperties and/or RenderFormSchema:
ensAddressPreview?: EnsAddressPreviewMode;

Prefer a first-class schema field over metadata for export stability and discoverability.

@openzeppelin/ui-renderer

RenderFormSchema.ensAddressPreview
    ↓
TransactionForm (read schema, provide context)
    ↓
DynamicFormField (blockchain-address)
    ├─ 'rich'  → BlockchainAddressDynamicField (Pattern A)
    └─ 'simple' → AddressField (current)

Thread mode through recursive DynamicFormField calls so nested object/array/map address fields inherit the form-level setting.

Default: ensAddressPreview omitted → 'simple'.


Implementation tasks

ui-types

  • Add EnsAddressPreviewMode type
  • Add optional ensAddressPreview to CommonFormProperties / RenderFormSchema
  • Export from package public API

ui-renderer

  • Create BlockchainAddressDynamicField (or equivalent) implementing Pattern A:
    • useWatchpreviewAddress
    • rich: AddressFieldWithResolvedPreview + ResolvedAddressFieldPreviewWithNameResolution
    • simple: AddressField
    • networkId from adapter / useAdapter() (existing patterns)
  • Add React context (or prop threading) from TransactionFormDynamicFormField for ensAddressPreview
  • Update fieldRegistry / DynamicFormField switch for blockchain-address
  • Graceful degradation when nameResolution missing (no throws)
  • rich without resolveAddress: forward resolution still works; preview card may be address-only

Tests

  • TransactionForm renders rich preview when ensAddressPreview: 'rich'
  • Default / omitted → simple announcer (snapshot or behavioral)
  • Nested blockchain-address fields inherit mode
  • Runtime without nameResolution → plain address field in both modes
  • Existing tests unaffected (default remains simple)

Docs / examples (optional but recommended)

  • Note in TransactionForm / form schema docs
  • Extend AddressFieldDemo or add minimal example showing schema flag

Acceptance criteria

  • ensAddressPreview: 'rich' on RenderFormSchema renders Pattern A below all blockchain-address fields in TransactionForm
  • Omitted or 'simple' matches current AddressField announcer behavior
  • No ecosystem === 'evm' conditionals introduced
  • Nested fields inherit form-level mode
  • Published package versions documented for ui-builder floor bump

References

Canonical Pattern A:

  • examples/basic-react-app/src/components/AddressFieldDemo.tsx
  • examples/basic-react-app/src/components/ENSResolutionDemo.tsx
  • packages/renderer/src/components/AddressBookWidget/AddAliasDialog.tsx
  • packages/renderer/src/components/ResolvedAddressFieldPreviewWithNameResolution.tsx
  • packages/components/src/components/AddressFieldWithResolvedPreview.tsx (verify path)

Current simple path:

  • packages/renderer/src/components/fieldRegistry.ts'blockchain-address': AddressField
  • packages/renderer/src/components/TransactionForm.tsx
  • packages/renderer/src/components/DynamicFormField.tsx

Name resolution hooks:

  • packages/react/src/hooks/nameResolution/useRuntimeNameResolver.ts

Downstream:


Open questions

  1. Should rich require resolveAddress, or is forward-only + address card acceptable when reverse is missing?
  2. Export BlockchainAddressDynamicField from @openzeppelin/ui-renderer public API so ui-builder can dedupe BlockchainAddressFieldWithRichPreview?
  3. Context vs explicit prop drilling for nested DynamicFormField — prefer context to avoid signature churn on every recursive call?

Release notes (draft)

Feature: RenderFormSchema.ensAddressPreview ('rich' | 'simple') controls ENS feedback UX for blockchain-address fields in TransactionForm. Default omitted → 'simple' (no breaking change).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions