Resolver widget
The drop-in <arcns-resolve> web component from @arcns/resolve-widget, with the script-tag and framework snippets, the attribute table, the events, the render states, theming, and accessibility.
<arcns-resolve> is a web component that does the whole resolve-and-render step for a recipient field, a search box or an explorer row: the user types @alice, alice.arc or alice.circle (or pastes a 0x… address) and the element shows the address, the namespace, the registry it was read from and the verified flag, then tells your code through an event. It wraps @arcns/resolve and follows the wallet recipe exactly; use it when you would rather not write that UI yourself. Package: @arcns/resolve-widget, MIT, 0.1.0-testnet.N on the testnet dist-tag.
Rule
The widget never shows a bare address. Every answer carries its namespace badge, the registry short-address and the verification badge, and a mixed shape such as @alice.arc is refused before any read. Resolution is single-registry and authoritative: .arc and .circle names resolve only against the FortiBlox ArcNS registry, so there is never a second registry's answer to weigh against it.
Drop it in
Not on npm yet
As of 2026-09-14, the @arcns npm scope has not been created — neither @arcns/resolve-widget nor @arcns/resolve is on the npm registry, so the CDN URL and npm install command below are the shape the install takes once they publish, not something that resolves today. Both packages are fully built in the sdk-widget/ and sdk/ directories of the (private) repository; until the first testnet release lands, that source is the only way to get the widget. To integrate today with no package at all, call the HTTP API directly.
One script tag, one element, once published. The IIFE build bundles the SDK and the parts of viem it needs; nothing else is loaded.
<script src="https://cdn.jsdelivr.net/npm/@arcns/resolve-widget@testnet/dist/arcns-resolve.iife.js"></script>
<arcns-resolve rpc-url="https://rpc.testnet.arc.io"></arcns-resolve>
<script>
document.addEventListener("arcns-resolve", (e) => {
const { name, namespace, registry, address, verified } = e.detail;
// enable "Send" only now, with all four on screen
});
document.addEventListener("arcns-error", (e) => {
// e.detail.code: not-found · no-record-for-chain · no-primary · ambiguous · tld-retired · rpc-error · …
});
</script>With a bundler, once published:
npm install @arcns/resolve-widget@testnet @arcns/resolve@testnet viemimport { defineArcnsResolve } from "@arcns/resolve-widget";
defineArcnsResolve(); // idempotent; a no-op during server-side rendering@arcns/resolve and viem are peer dependencies of the ESM build.
What it shows
| State | On screen |
|---|---|
| idle | a hint naming the accepted shapes |
| invalid | the rule the input breaks (A hyphen cannot start or end a name.), or that @name.arc is two different names. Nothing is looked up while the user is still typing. |
| loading | Resolving alice.arc…; the region is aria-busy |
| resolved | namespace badge (@handle, .arc, .circle), the canonical name, Verified or Unverified, the checksummed address with a copy button, and registry 0x0a1D…2FE4 · ArcNS; · ETH record when the coin-type-60 fallback answered |
| not-found | alice.arc is not registered., or @arcns is registered but has no ARC address record. Nothing to send to., or 0x0b94…209D has no primary name (…) |
| error | Couldn't read the chain. Try again. with Retry; a retired TLD; a missing configuration |
The state is mirrored to a state attribute on the element, so a page can style arcns-resolve[state="resolved"]. The status area reserves its height, so moving between states never shifts the content below it.
verified on the badge
Forward (name to address): Verified means the owner proved control of that address for that coin type on chain, verified(node, coinType) on the ArcNS resolver. Unverified means a record exists but nobody proved it: the badge is a warning and its tooltip says so. The name's controller is never shown as a payment address.
Reverse (address to name): a primary is returned only after it forward-confirms, so the badge is always Verified and the tooltip reads "forward-confirmed". An address whose primary no longer confirms is not-found, never the stale name. This is the same meaning the API gives addr.verified and the reverse route's verified: true; the full definition is on Verified records.
Single registry, one answer
.arc and .circle lookups resolve only against the FortiBlox ArcNS registry — single-registry, winner-take-all (CEO decision 2026-09-09), the same rule the SDK and the API apply. There is no resolveAll(), no second registry to compare against, and no per-row Use button: a name this registry does not hold is a plain not-found, exactly like any other unregistered name. An earlier build of the widget rendered a multi-registry ambiguous/conflict state with candidates and picked fields on the events; all of that has been removed. ambiguous now names only the mixed-shape refusal below.
Attributes
Every attribute has a camelCase property (rpc-url is rpcUrl).
Prop
Type
Properties only: resolver (a shared @arcns/resolve Resolver; overrides rpc-url and chain-id), state, result, focus(), refresh().
Reads through api-url are free for the ArcNS sites (arcns.io, app.arcns.io, docs.arcns.io) and for callers presenting an ArcNS-issued X-API-Key; every other origin gets 402 Payment Required and is charged per call over x402 — see Agents: pay per read with x402. The widget has no x402 client built in, so a 402 from a non-first-party api-url renders as a plain error state, not a retry or a payment prompt. If you're embedding on a site other than the ones above, use rpc-url instead (the SDK reads the chain directly and is always free) or front api-url with your own paying proxy.
Events
Both bubble and are composed, so one listener on document covers every instance.
| Event | detail |
|---|---|
arcns-resolve | { input, mode, name, namespace, registry, product, address, verified, chainId, coinType? } |
arcns-error | { input, code, message, reason?, status? }; code is one of not-found, no-record-for-chain, no-primary, ambiguous, tld-retired, rpc-error, not-configured, http-error |
Invalid input while typing emits nothing; the mixed shape @name.arc does emit ambiguous, because it is a decision rather than a typo. A lookup the user has typed past emits nothing at all: fetch requests are aborted and RPC answers are discarded.
Frameworks
The element is plain DOM. Register it once on the client, then use the tag.
import { useEffect, useRef } from "react";
import { defineArcnsResolve, type ArcnsResolveDetail, type ArcnsResolveElement } from "@arcns/resolve-widget";
export function Recipient({ onAddress }: { onAddress: (d: ArcnsResolveDetail) => void }) {
const ref = useRef<ArcnsResolveElement>(null);
useEffect(() => {
defineArcnsResolve();
const el = ref.current!;
const handler = (e: CustomEvent<ArcnsResolveDetail>) => onAddress(e.detail);
el.addEventListener("arcns-resolve", handler);
return () => el.removeEventListener("arcns-resolve", handler);
}, [onAddress]);
return <arcns-resolve ref={ref} rpc-url="https://rpc.testnet.arc.io" mode="resolve" />;
}No React dependency in the package. React 19 passes custom-element attributes through as written; on React 18 declare the tag in JSX.IntrinsicElements and keep the addEventListener above.
Theming
Styles live in the shadow root and read custom properties from the page. Each defaults to the ArcNS brand token for the active theme, and every text and background pair in both themes meets WCAG AA.
arcns-resolve {
--arcns-bg: #fffefc;
--arcns-fg: #1b1816;
--arcns-fg-muted: #6b635c;
--arcns-border: rgba(27, 24, 22, 0.18);
--arcns-accent: #b93d0a;
--arcns-ok: #1f7a3a;
--arcns-warn: #a12d5e;
--arcns-radius: 12px;
--arcns-font: "Geist", system-ui, sans-serif;
--arcns-font-mono: "Geist Mono", ui-monospace, monospace;
--arcns-status-min-height: 6.25rem;
}Also --arcns-surface, --arcns-fg-secondary, --arcns-accent-soft, --arcns-accent-strong (accent text on the tinted namespace badge; #35c5ff in dark, because the base accent falls below AA on the tint), --arcns-accent-contrast, --arcns-ok-soft, --arcns-warn-soft. CSS parts for deeper changes: root, field, input, status, result, namespace, verified, address, copy, meta.
Accessibility
A real <label> (the label attribute, visually hidden); the status area is role="status" aria-live="polite" and referenced from the input by aria-describedby; aria-invalid and aria-busy follow the state; badges carry text, with the verification meaning in the tooltip and read to screen readers; every control is a <button> with a name; the input is 44 px tall; one :focus-visible ring; prefers-reduced-motion collapses the spinner.
Questions
Questions: [email protected].