Advanced Usage
A couple of patterns that come up once you have used the SDK for a bit.
A Reusable Token Selector
Building a swap form, a bridge, or anything with a "from" and "to" token? You will want a small wrapper so you are not copy-pasting SelectTokenModal everywhere.
Step 1: Wrap it
1// components/ReusableSelectToken.tsx2import { ReactNode } from 'react';3import { SelectTokenModal, IToken } from 'starknet-tokenkit';4 5interface IReusableSelectToken {6 selectedToken: IToken | null;7 callBackFn: (token: IToken) => void;8 children: ReactNode;9}10 11const ReusableSelectToken = (props: IReusableSelectToken) => {12 return (13 <SelectTokenModal14 selectedToken={props.selectedToken}15 callBackFunc={props.callBackFn}16 >17 {props.children}18 </SelectTokenModal>19 );20};21 22export default ReusableSelectToken;Step 2: Use it in a swap form
Now your swap page is just two pickers, no boilerplate:
1import { useState } from 'react';2import { TokenKitWrapper, IToken, themes } from 'starknet-tokenkit';3import ReusableSelectToken from './components/ReusableSelectToken';4 5function SwapPage() {6 const [fromToken, setFromToken] = useState<IToken | null>(null);7 const [toToken, setToToken] = useState<IToken | null>(null);8 9 return (10 <TokenKitWrapper11 network="SN_MAIN"12 apiKey="your-api-key"13 mainnetEndpoint="https://api.tokenkithq.io"14 sepoliaEndpoint="https://api.sepolia.tokenkithq.io"15 themeObject={themes.dark}16 >17 <div className="swap-container">18 {/* From Token */}19 <ReusableSelectToken selectedToken={fromToken} callBackFn={setFromToken}>20 <button>{fromToken ? fromToken.symbol : 'Select From Token'}</button>21 </ReusableSelectToken>22 23 {/* To Token */}24 <ReusableSelectToken selectedToken={toToken} callBackFn={setToToken}>25 <button>{toToken ? toToken.symbol : 'Select To Token'}</button>26 </ReusableSelectToken>27 </div>28 </TokenKitWrapper>29 );30}Reading the wrapper config
If you need to make your own API call with the same network and key the SDK is using, grab them from useTokenKitContext:
1import { useTokenKitContext } from 'starknet-tokenkit';2 3const MyHoldings = () => {4 const {5 network,6 apiKey,7 mainnetEndpoint,8 sepoliaEndpoint,9 options, // { tokensToLoad, enableRecent }10 origin, // optional X-Origin header value11 } = useTokenKitContext();12 13 const endpoint = network === 'SN_MAIN' ? mainnetEndpoint : sepoliaEndpoint;14 15 // Reuse the same credentials the picker uses16 const headers: HeadersInit = { 'api-key': apiKey ?? '' };17 if (origin) headers['X-Origin'] = origin;18 19 // fetch(`${endpoint}/api/balances/`, { headers, ... })20 return <p>Connected to {network}</p>;21};Useful for keeping things in sync without passing the config around manually. Note every value can be null until the wrapper is mounted, so guard accordingly when calling from libraries.
Browser-extension wallets — origin
If you're building a browser-extension wallet, set origin on TokenKitWrapper. The SDK forwards it as the X-Origin request header to the API — your API key can then be restricted to only that extension ID.
1<TokenKitWrapper2 /* ...other props */3 origin={`chrome-extension://${chrome.runtime.id}`}4>Web apps almost always don't need this; the browser's natural Origin header is enough.
Picking which token set to load — options.tokensToLoad
The picker defaults to 'public', which is the curated set anyone listing through tokenkithq.io will appear in. If your dApp lets users paste arbitrary contract addresses and look them up (e.g. an admin tool, an explorer), switch to 'all':
1<TokenKitWrapper2 /* ...other props */3 options={{ tokensToLoad: 'all' }}4>'all' includes every indexed ERC-20 we've seen, verified or not. Default to 'public' for end-user surfaces — 'all' will surface scams in the search results.
Opting into recent tokens — options.enableRecent
Recent-token persistence is off by default. When enabled, the picker writes the last few picks to localStorage (keyed by network) and shows a "Recent" section above the full list.
1<TokenKitWrapper2 /* ...other props */3 options={{ enableRecent: true }}4>The user can clear their own list with the "Clear all" button next to the section header, or remove individual entries with the × on each row.