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-address → AddressField 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 useRuntimeNameResolver → EMPTY_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
ui-renderer
Tests
Docs / examples (optional but recommended)
Acceptance criteria
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
- Should rich require
resolveAddress, or is forward-only + address card acceptable when reverse is missing?
- Export
BlockchainAddressDynamicField from @openzeppelin/ui-renderer public API so ui-builder can dedupe BlockchainAddressFieldWithRichPreview?
- 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).
Summary
Add a form-level setting so
TransactionForm/DynamicFormFieldcan renderblockchain-addressfields with either:richAddressFieldWithResolvedPreview+ResolvedAddressFieldPreviewWithNameResolution+ parentuseWatchsimpleAddressFieldwith inline “Resolved to0x…” announcer (current behavior)Today
fieldRegistrymapsblockchain-address→AddressFieldonly. Rich preview exists elsewhere (Address BookAddAliasDialog, basic-react-app demos) but is not available toTransactionFormconsumers (ui-builder form preview, exported apps, direct integrators).Downstream tracking: OpenZeppelin/ui-builder#403 (Phase 2 — builder toggle, export schema, tests).
Motivation
@openzeppelin/ui-rendererkeeps builder preview, exported apps, and anyTransactionFormconsumer alignedDesign principles
Capability-led, not ecosystem-specific. Gate behavior on
EcosystemRuntime.nameResolution(resolveName/resolveAddressperNameResolutionCapabilityin@openzeppelin/ui-types). Do not branch onnetworkConfig.ecosystem === 'evm'.When
nameResolutionis absent, both modes degrade to plain address input (existinguseRuntimeNameResolver→EMPTY_RESOLVERbehavior).Proposed API
@openzeppelin/ui-typesPrefer a first-class schema field over
metadatafor export stability and discoverability.@openzeppelin/ui-rendererThread mode through recursive
DynamicFormFieldcalls so nested object/array/map address fields inherit the form-level setting.Default:
ensAddressPreviewomitted →'simple'.Implementation tasks
ui-typesEnsAddressPreviewModetypeensAddressPreviewtoCommonFormProperties/RenderFormSchemaui-rendererBlockchainAddressDynamicField(or equivalent) implementing Pattern A:useWatch→previewAddressrich:AddressFieldWithResolvedPreview+ResolvedAddressFieldPreviewWithNameResolutionsimple:AddressFieldnetworkIdfrom adapter /useAdapter()(existing patterns)TransactionForm→DynamicFormFieldforensAddressPreviewfieldRegistry/DynamicFormFieldswitch forblockchain-addressnameResolutionmissing (no throws)richwithoutresolveAddress: forward resolution still works; preview card may be address-onlyTests
TransactionFormrenders rich preview whenensAddressPreview: 'rich'blockchain-addressfields inherit modenameResolution→ plain address field in both modesDocs / examples (optional but recommended)
TransactionForm/ form schema docsAddressFieldDemoor add minimal example showing schema flagAcceptance criteria
ensAddressPreview: 'rich'onRenderFormSchemarenders Pattern A below allblockchain-addressfields inTransactionForm'simple'matches currentAddressFieldannouncer behaviorecosystem === 'evm'conditionals introducedReferences
Canonical Pattern A:
examples/basic-react-app/src/components/AddressFieldDemo.tsxexamples/basic-react-app/src/components/ENSResolutionDemo.tsxpackages/renderer/src/components/AddressBookWidget/AddAliasDialog.tsxpackages/renderer/src/components/ResolvedAddressFieldPreviewWithNameResolution.tsxpackages/components/src/components/AddressFieldWithResolvedPreview.tsx(verify path)Current simple path:
packages/renderer/src/components/fieldRegistry.ts—'blockchain-address': AddressFieldpackages/renderer/src/components/TransactionForm.tsxpackages/renderer/src/components/DynamicFormField.tsxName resolution hooks:
packages/react/src/hooks/nameResolution/useRuntimeNameResolver.tsDownstream:
BuilderFormConfig, export@@FORM_SCHEMA_JSON@@Open questions
resolveAddress, or is forward-only + address card acceptable when reverse is missing?BlockchainAddressDynamicFieldfrom@openzeppelin/ui-rendererpublic API so ui-builder can dedupeBlockchainAddressFieldWithRichPreview?DynamicFormField— prefer context to avoid signature churn on every recursive call?Release notes (draft)