@liberfi.io/ui-chain-select
v0.1.83
Published
Chain Management for Liberfi React SDK
Readme
@liberfi.io/ui-chain-select
Chain selection UI and state management for the Liberfi React SDK. Provides a responsive chain selector widget (desktop popover / mobile icon buttons), Jotai-based state atoms, and hooks for reading and switching the current chain. Consumed by app-level packages and widgets that need chain-aware behaviour.
Design Philosophy
- State / Hooks / UI layering — Jotai atoms own the chain state; hooks read/write atoms and invoke callbacks; the widget wires them together; UI components are purely presentational and can be used independently.
- Inversion of control — All side effects (wallet switching, toast, analytics) are delegated to the caller via
onSwitchChain,onSuccess, andonErrorcallbacks. The package never hardcodes feedback. - Optional Provider — Works out of the box with default atoms (zero-config). Wrap with
ChainSelectProvideronly when multiple independent chain selectors need to coexist (differentstorageKeyPrefix). - Single source of truth —
ChainandChainNamespacetypes come from@liberfi.io/types; display names, colors, icons, andchainToNamespacecome from@liberfi.io/utilsand@liberfi.io/ui.
Installation
pnpm add @liberfi.io/ui-chain-selectPeer dependencies
The consumer must provide:
| Package | Version |
| ---------------- | --------- |
| react | >= 18 |
| react-dom | >= 18 |
| jotai | >= 2.15.1 |
| @liberfi.io/ui | workspace |
API Reference
Components
ChainSelectWidget
Full-featured chain selector that wires state and callbacks. Drop-in usage — no Provider required.
function ChainSelectWidget(props: ChainSelectWidgetProps): JSX.Element;| Prop | Type | Default | Description |
| --------------- | --------------------------------- | ----------------------------- | ----------------------------------- |
| size | "sm" \| "md" \| "lg" | undefined | Button / item size |
| className | string | undefined | Class on the root element |
| candidates | Chain[] | [SOLANA, ETHEREUM, BINANCE] | Chains to offer |
| onSwitchChain | (chain: Chain) => Promise<void> | undefined | Async handler (e.g. wallet switch) |
| onSuccess | (chain: Chain) => void | undefined | Called after successful switch |
| onError | (error: unknown) => void | undefined | Called when onSwitchChain rejects |
ChainSelectUI
Presentational responsive shell. Renders ChainSelectDesktopUI or ChainSelectMobileUI based on viewport.
function ChainSelectUI(props: ChainSelectUIProps): JSX.Element;| Prop | Type | Default | Description |
| --------------- | ----------------------------------------- | -------------------- | ------------------------- |
| size | "sm" \| "md" \| "lg" | undefined | Button / item size |
| chain | Chain | candidates[0] | Currently selected chain |
| candidates | Chain[] | DEFAULT_CANDIDATES | Chains to show |
| onSelectChain | (chain: Chain) => void \| Promise<void> | undefined | Selection handler |
| isSwitching | boolean | undefined | Shows loading state |
| className | string | undefined | Class on the root element |
ChainAvatar
Renders a chain icon. Uses dedicated SVG icons for known chains, falls back to an Avatar with the chain's icon URL.
function ChainAvatar(props: ChainAvatarProps): JSX.Element;| Prop | Type | Description |
| ----------- | -------- | -------------------------- |
| chain | Chain | The chain to display |
| className | string | Class on the icon / avatar |
ChainSelectProvider
Optional context provider for multi-instance scenarios.
function ChainSelectProvider(props: ChainSelectProviderProps): JSX.Element;| Prop | Type | Default | Description |
| ------------------ | ----------- | ------- | ---------------------------- |
| storageKeyPrefix | string | "" | Prefix for localStorage keys |
| children | ReactNode | — | Children |
Hooks
useSelectChain
Returns a selectChain function and isSwitching state.
function useSelectChain(options?: UseSelectChainOptions): {
selectChain: (chain: Chain) => Promise<void>;
isSwitching: boolean;
};| Option | Type | Description |
| --------------- | --------------------------------- | ----------------------------------- |
| onSwitchChain | (chain: Chain) => Promise<void> | Async handler before state update |
| onSuccess | (chain: Chain) => void | Called after successful switch |
| onError | (error: unknown) => void | Called when onSwitchChain rejects |
useCurrentChain
Reads the current chain and namespace from state.
function useCurrentChain(): {
chain: Chain;
chainNamespace: ChainNamespace;
};State (Jotai atoms)
| Export | Type | Description |
| -------------------- | --------------------------------- | ----------------------------------------------- |
| chainAtom | WritableAtom<Chain> | Default chain atom (key "chain") |
| chainNamespaceAtom | WritableAtom<ChainNamespace> | Default namespace atom (key "chainNamespace") |
| defaultChainAtoms | ChainAtoms | Bundle of both default atoms |
| createChainAtoms | (prefix?: string) => ChainAtoms | Factory for custom-prefixed atoms |
Types
| Export | Description |
| ------------------------------ | ----------------------------------- |
| ChainAtoms | { chainAtom, chainNamespaceAtom } |
| ChainSelectStateContextValue | Context value type |
| ChainSelectProviderProps | Props for ChainSelectProvider |
| ChainSelectWidgetProps | Props for ChainSelectWidget |
| ChainSelectUIProps | Props for ChainSelectUI |
| ChainAvatarProps | Props for ChainAvatar |
| UseSelectChainOptions | Options for useSelectChain |
Usage Examples
Basic usage
import { ChainSelectWidget } from "@liberfi.io/ui-chain-select";
function App() {
return (
<ChainSelectWidget
onSwitchChain={async (chain) => {
await wallet.switchChain(chain);
}}
onSuccess={(chain) => toast.success(`Switched to ${chain}`)}
onError={(err) => toast.error("Switch failed")}
/>
);
}Presentational-only (no state management)
import { Chain } from "@liberfi.io/types";
import { ChainSelectUI } from "@liberfi.io/ui-chain-select";
function ReadOnlyChainDisplay() {
return (
<ChainSelectUI
chain={Chain.ETHEREUM}
candidates={[Chain.ETHEREUM, Chain.BINANCE]}
onSelectChain={(chain) => console.log(chain)}
/>
);
}Multiple independent instances
import {
ChainSelectProvider,
ChainSelectWidget,
} from "@liberfi.io/ui-chain-select";
function MultiChainApp() {
return (
<>
<ChainSelectProvider storageKeyPrefix="source_">
<ChainSelectWidget onSwitchChain={handleSourceSwitch} />
</ChainSelectProvider>
<ChainSelectProvider storageKeyPrefix="target_">
<ChainSelectWidget onSwitchChain={handleTargetSwitch} />
</ChainSelectProvider>
</>
);
}Reading current chain from hooks
import { useCurrentChain } from "@liberfi.io/ui-chain-select";
function ChainInfo() {
const { chain, chainNamespace } = useCurrentChain();
return (
<p>
Current: {chain} ({chainNamespace})
</p>
);
}Future Improvements
- Refactor
version.tsmodule-level side effect to a lazy registration pattern (monorepo-wide change).
