diff --git a/.changeset/icon-load-fallback.md b/.changeset/icon-load-fallback.md new file mode 100644 index 000000000..21c62a0f6 --- /dev/null +++ b/.changeset/icon-load-fallback.md @@ -0,0 +1,5 @@ +--- +'@relayprotocol/relay-kit-ui': patch +--- + +Gracefully handle broken token/chain logo images. ChainTokenIcon now falls back to the token symbol avatar and ChainIcon hides itself when the logo fails to load, instead of rendering a broken-image placeholder. diff --git a/packages/ui/src/components/primitives/ChainIcon.tsx b/packages/ui/src/components/primitives/ChainIcon.tsx index d0d279250..1d0a10d30 100644 --- a/packages/ui/src/components/primitives/ChainIcon.tsx +++ b/packages/ui/src/components/primitives/ChainIcon.tsx @@ -1,4 +1,4 @@ -import { useContext, type FC } from 'react' +import { useContext, useState, type FC } from 'react' import useRelayClient from '../../hooks/useRelayClient.js' import { ProviderOptionsContext } from '../../providers/RelayKitProvider.js' import { cn } from '../../utils/cn.js' @@ -20,6 +20,7 @@ const ChainIcon: FC = ({ square = true, borderRadius = 4 }) => { + const [erroredSrc, setErroredSrc] = useState(null) const providerOptions = useContext(ProviderOptionsContext) const client = useRelayClient() const chain = chainId @@ -35,7 +36,7 @@ const ChainIcon: FC = ({ const iconUrl = square && icon ? icon.replace('/icons/', '/icons/square/') : icon - return iconUrl ? ( + return iconUrl && erroredSrc !== iconUrl ? (
= ({ {`Chain setErroredSrc(iconUrl ?? null)} style={{ borderRadius: square ? borderRadius : 0, width: '100%', diff --git a/packages/ui/src/components/primitives/ChainTokenIcon.tsx b/packages/ui/src/components/primitives/ChainTokenIcon.tsx index e7e6cd1fa..c2df20291 100644 --- a/packages/ui/src/components/primitives/ChainTokenIcon.tsx +++ b/packages/ui/src/components/primitives/ChainTokenIcon.tsx @@ -1,4 +1,4 @@ -import { type FC } from 'react' +import { type FC, useState } from 'react' import ChainIcon from './ChainIcon.js' import Text from './Text.js' import { cn } from '../../utils/cn.js' @@ -43,7 +43,11 @@ export const ChainTokenIcon: FC = ({ chainRadius = 4, chainIconSize }) => { - const isValidTokenLogo = tokenlogoURI && tokenlogoURI !== 'missing.png' + const [erroredSrc, setErroredSrc] = useState(null) + const isValidTokenLogo = + tokenlogoURI && + tokenlogoURI !== 'missing.png' && + erroredSrc !== tokenlogoURI const dimensions = SIZES[size] const chainSize = chainIconSize ?? dimensions.chain @@ -65,6 +69,7 @@ export const ChainTokenIcon: FC = ({ src={tokenlogoURI} width={dimensions.token} height={dimensions.token} + onError={() => setErroredSrc(tokenlogoURI ?? null)} style={{ borderRadius: 9999, overflow: 'hidden'