OpenZeppelin / OpenZeppelin/ui-builder
feat(builder): configurable ENS address preview mode (rich vs simple) for forms
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 48
- Forks
- 23
- Avg merge
- 3h 1m
- Merged PRs (30d)
- 10
Description
Summary
Form preview and exported apps currently use TransactionForm → DynamicFormField → bare AddressField, which shows the simple ENS forward-resolution UX (inline “Resolved to 0x…” text + optional cross-network disclaimer — see screenshot in PR #401 discussion).
Builder-specific surfaces already use Pattern A (rich preview card with avatar via AddressFieldWithResolvedPreview + ResolvedAddressFieldPreviewWithNameResolution + useWatch), e.g.:
apps/builder/src/components/fields/BlockchainAddressFieldWithRichPreview.tsx- Address book Add Alias (internal to
AddressBookWidget/AddAliasDialogin ui-renderer ≥3.4.0)
Gap: end-user transaction forms (preview + export) never take the rich path because packages/renderer/src/components/fieldRegistry.ts maps blockchain-address → AddressField.
We want a form-level builder setting so users can choose:
| Mode | UX |
|---|---|
rich (new default for new forms) |
Pattern A preview card (name + avatar) below address inputs |
simple (current behavior; preserve for existing exports) |
Inline “Resolved to 0x…” announcer |
Motivation
- Parity between builder preview, exported apps, and rich ENS surfaces (address book, EOA config)
- User control over visual density / branding
- Safe rollout: existing saved/exported forms should not change appearance unless opted in
Architecture (constitution-compliant)
Per .specify/memory/constitution.md Principle I (chain-agnostic, adapter-led):
- Do NOT gate on
ecosystem === 'evm'or chain id strings - Do use runtime capabilities:
runtime?.nameResolution(NameResolutionCapability) - Feature detection is structural per ui-types:
capability.resolveName,capability.resolveAddress - When capability is absent, components degrade gracefully (existing SF-3 behavior via empty
NameResolver)
Data flow
Builder UI toggle (General Settings)
↓
BuilderFormConfig.ensAddressPreview: 'rich' | 'simple'
↓
FormSchemaFactory.builderConfigToRenderSchema()
↓
RenderFormSchema.ensAddressPreview (serialized into export @@FORM_SCHEMA_JSON@@)
↓
TransactionForm reads schema → DynamicFormField → blockchain-address field
↓
'rich' → AddressFieldWithResolvedPreview + ResolvedAddressFieldPreviewWithNameResolution
'simple' → AddressField (current)
Capability-led UI gating (builder only)
Show the setting when the active runtime supports forward name resolution:
const canResolveNames = Boolean(runtime?.nameResolution?.resolveName);
Optional: only advertise rich when resolveAddress is also present; otherwise rich degrades to address-only card.
Hide control when !canResolveNames — because the adapter didn’t publish name resolution, not because of ecosystem string checks.
Upstream dependency (openzeppelin-ui)
This feature requires renderer support — builder-only wrappers will not fix exported apps.
Phase 1 — @openzeppelin/ui-types
Add typed setting (prefer first-class field over metadata):
export type EnsAddressPreviewMode = 'rich' | 'simple';
// On CommonFormProperties or RenderFormSchema:
ensAddressPreview?: EnsAddressPreviewMode;
Phase 2 — @openzeppelin/ui-renderer
- Implement
BlockchainAddressDynamicField(or equivalent) withuseWatch+ mode switch - Wire from
DynamicFormFieldwhenfield.type === 'blockchain-address' - Thread mode through nested
DynamicFormFieldrecursion (object/array/map children) TransactionFormreadsschema.ensAddressPreviewand provides context- Defaults:
undefined/ omitted →'simple'(backward compat for existing exports)- explicit
'rich'→ Pattern A - explicit
'simple'→ current announcer
Reference implementations:
openzeppelin-ui/examples/basic-react-app/src/components/AddressFieldDemo.tsxopenzeppelin-ui/packages/renderer/src/components/AddressBookWidget/AddAliasDialog.tsxopenzeppelin-ui/packages/renderer/src/components/ResolvedAddressFieldPreviewWithNameResolution.tsx
Phase 3 — ui-builder (this repo)
- Extend
BuilderFormConfig/ persist viaContractUIRecord.formConfig - UI: radio in General Settings (or ENS subsection) — Rich vs Simple
- Default new forms to
'rich'; treat missing field as'simple'for loaded records FormPreview.tsx— no structural change once renderer supports schema field- Export — schema JSON already embedded via
form-component.template.tsx; updateEnsExportPins.verification.test.ts/ snapshots - Consolidate
BlockchainAddressFieldWithRichPreview.tsxto re-use upstream field component once available - Bump ui-renderer floor when upstream ships
Out of scope / anti-patterns
- ❌ Forking
TransactionFormonly in builder (export diverges) - ❌ Patching
fieldRegistryonly in export templates - ❌ Defaulting existing schemas to
'rich'without migration - ❌
if (ecosystem === 'evm')conditionals anywhere in UI
Acceptance criteria
- Builder toggle visible only when
runtime.nameResolution?.resolveNameis present - Form preview reflects selected mode for
blockchain-addressfields - Exported app
formSchemaincludesensAddressPreviewand matches preview - Existing Contract UI records without the field render as simple (unchanged)
- New forms default to rich when name resolution is available
- Non-capable networks: address fields work; rich mode degrades safely
- ENS 003 mainnet L1 fallback: simple mode keeps announcer + disclaimer; rich mode uses preview card
- Tests: renderer unit tests (both modes), builder export pin/snapshot tests, manual QA on Sepolia +
pasevin.eth
Related work
- PR #401 — ENS featureset + rich preview on builder-specific surfaces (
feat/ens-mainnet-l1-fallback-003) - openzeppelin-ui PR #195 — network-scoped ENS resolution (ui-renderer 3.4.0)
- Pattern A reference:
BlockchainAddressFieldWithRichPreview.tsx,AddressBookDialog.tsx
Suggested sequencing
- openzeppelin-ui issue/PR: types + renderer implementation + tests
- ui-builder follow-up on PR #401 (or stacked PR): UI toggle, schema plumbing, floor bump, snapshots
Labels
enhancement, ens, export, ui-renderer-dependency
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the data flow in this issue, .specify/memory/constitution.md, and the named builder files, then review the upstream ui-types and ui-renderer work required before changing ui-builder. Trace BuilderFormConfig through FormSchemaFactory.builderConfigToRenderSchema(), FormPreview.tsx, and form-component.template.tsx. Done means the toggle, serialized schema, preview, export behavior, compatibility defaults, and listed tests agree across supported runtimes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- blockchain, react, typescript
- Domain
- blockchain, frontend, tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100