Generative UI Generative UI enables Nex-T1 to stream rich, interactive UI components alongside text responses. Instead of just returning data, the AI generates complete, ready-to-render React components for charts, tables, wallet views, and transaction interfaces. 
What is Generative UI? Generative UI is a paradigm where AI agents don’t just return text or JSON data—they stream fully-formed UI components directly to your frontend. When a user asks “Show me ETH price charts for the last 30 days,” Nex-T1: 
Fetches the data from on-chain sources 
Generates a complete chart component with the data 
Streams it to your frontend as a UI block 
Your app renders it instantly 
 
This creates seamless, natural interactions where the AI understands not just what data to show, but how to visualize it. 
Why Generative UI for Web3? 
Context-Aware Visualizations AI chooses the best visualization based on user intent: 
Price queries → Line charts 
Portfolio analysis → Holdings tables 
Token comparisons → Comparison grids 
Transaction history → Timeline views 
 
Zero Manual Formatting No need to parse API responses and format data: 
Components arrive ready-to-render 
Data is pre-formatted and validated 
Styling matches component type 
Responsive by default 
 
Interactive Elements Generate actionable UI components: 
Swap forms with pre-filled data 
Sign request dialogs 
Transaction status trackers 
Approval workflows 
 
Streaming Updates Real-time component delivery: 
Progressive rendering as data arrives 
Multiple components per response 
Mixed text and UI content 
Event-driven architecture 
 Architecture How It Works Component Generation Process 
Intent Recognition : Agent identifies what visualization is neededData Fetching : Retrieves data from appropriate sourcesSchema Generation : Creates UI block following app/schemas/ui.pyStreaming : Sends UI block as JSON eventFrontend Rendering : Your app maps ui.kind to React component 
Stream Event Types The streaming API returns three types of events: 
 Text Events
 UI Events
 End Events
{   "event" :  "text" ,   "content" :  "Here's the ETH price chart..." ,   "done" :  false } Regular text tokens for conversational responses. Available UI Components Chart Components  Price Chart
 Volume Chart
 Candlestick Chart
Component Type : price_chartProps :{   kind :  'price_chart' ;   title ?:  string ;   symbol ?:  string ;   pair ?:  string ;           // e.g., "ETH/USDC"   currency ?:  string ;       // e.g., "USD"   range ?:  string ;          // e.g., "30d", "1y"   data :  Array <{     t :  string ;             // ISO timestamp     price :  number ;   }>; } Use Cases :
Token price history 
Multi-timeframe analysis 
Price comparison overlays 
 Example :import  {  LineChart ,  Line ,  XAxis ,  YAxis ,  Tooltip  }  from  'recharts' ; export  function  PriceChart ({  title ,  symbol ,  data  } :  PriceChartProps ) {   return  (     < div  className = "chart-container" >       < h3 > { title  ||  ` ${ symbol }  Price Chart` } </ h3 >       < LineChart  width = { 600 }  height = { 300 }  data = { data } >         < XAxis  dataKey = "t"  />         < YAxis  />         < Tooltip  />         < Line  type = "monotone"  dataKey = "price"  stroke = "#8884d8"  />       </ LineChart >     </ div >   ); } Table Components  Asset Table
 Wallet Holdings
 Wallet Balance
Component Type : asset_tableProps :{   kind :  'asset_table' ;   title ?:  string ;   rows :  Array <{     symbol :  string ;     name ?:  string ;     price ?:  number ;     change_24h_pct ?:  number ;     volume_24h ?:  number ;     logo_url ?:  string ;   }>; } Use Cases :
Token lists and rankings 
Market comparisons 
Watchlist displays 
 Example :export  function  AssetTable ({  title ,  rows  } :  AssetTableProps ) {   return  (     < div  className = "asset-table" >       < h3 > { title  ||  'Assets' } </ h3 >       < table >         < thead >           < tr >             < th > Token </ th >             < th > Price </ th >             < th > 24h Change </ th >             < th > Volume </ th >           </ tr >         </ thead >         < tbody >           { rows . map (( row )  =>  (             < tr  key = { row . symbol } >               < td >                 { row . logo_url  &&  < img  src = { row . logo_url }  alt = { row . symbol }  /> }                 { row . name }  ( { row . symbol } )               </ td >               < td > $ { row . price ?. toFixed ( 2 ) } </ td >               < td  className = { row . change_24h_pct  >=  0  ?  'positive'  :  'negative' } >                 { row . change_24h_pct ?. toFixed ( 2 ) } %               </ td >               < td > $ { row . volume_24h ?. toLocaleString () } </ td >             </ tr >           )) }         </ tbody >       </ table >     </ div >   ); } Wallet & Transaction Components  Wallet PnL
 Sign Request
 Token Logo
Component Type : wallet_pnlProps :{   kind :  'wallet_pnl' ;   wallet_address :  string ;   period ?:  string ;          // e.g., "24h", "7d", "30d"   pnl_usd ?:  number ;   pnl_pct ?:  number ;   timeseries ?:  Array <{     t :  string ;     pnl_usd :  number ;   }>; } Use Cases :
Portfolio performance tracking 
Profit/loss visualization 
Historical performance analysis 
 Example :export  function  WalletPnL ({  wallet_address ,  period ,  pnl_usd ,  pnl_pct ,  timeseries  } :  WalletPnLProps ) {   const  isPositive  =  pnl_usd  >=  0 ;   return  (     < div  className = "wallet-pnl" >       < h3 > PnL for  { wallet_address . slice ( 0 ,  6 ) } ... { wallet_address . slice ( - 4 ) } </ h3 >       < div  className = { `pnl-summary  ${ isPositive  ?  'positive'  :  'negative' } ` } >         < span  className = "pnl-amount" > { isPositive  ?  '+'  :  '' } $ { pnl_usd ?. toFixed ( 2 ) } </ span >         < span  className = "pnl-pct" > { isPositive  ?  '+'  :  '' }{ pnl_pct ?. toFixed ( 2 ) } % </ span >         < span  className = "period" > { period } </ span >       </ div >       { timeseries  &&  (         < LineChart  width = { 400 }  height = { 200 }  data = { timeseries } >           < Line  type = "monotone"  dataKey = "pnl_usd"  stroke = { isPositive  ?  '#10b981'  :  '#ef4444' }  />         </ LineChart >       ) }     </ div >   ); } NFT Components Component Type : nft_gridProps :{   kind :  'nft_grid' ;   title ?:  string ;   items :  Array <{     token_id ?:  string ;     name ?:  string ;     collection ?:  string ;     image_url ?:  string ;     permalink ?:  string ;      // Link to marketplace   }>; } Use Cases :
NFT collection displays 
Gallery views 
Wallet NFT portfolios 
 Example :export  function  NftGrid ({  title ,  items  } :  NftGridProps ) {   return  (     < div  className = "nft-grid" >       < h3 > { title  ||  'NFTs' } </ h3 >       < div  className = "grid" >         { items . map (( nft ,  idx )  =>  (           < a             key = { nft . token_id  ||  idx }             href = { nft . permalink }             target = "_blank"             rel = "noopener noreferrer"             className = "nft-card"           >             { nft . image_url  &&  (               < img  src = { nft . image_url }  alt = { nft . name  ||  'NFT' }  />             ) }             < div  className = "nft-info" >               < div  className = "nft-name" > { nft . name  ||  `# ${ nft . token_id } ` } </ div >               { nft . collection  &&  (                 < div  className = "nft-collection" > { nft . collection } </ div >               ) }             </ div >           </ a >         )) }       </ div >     </ div >   ); } Implementation Guide 1. Setting Up the Frontend Install Dependencies :npm  install  recharts  @solana/wallet-adapter-react  ethers Create UIBlockRenderer :// components/UIBlockRenderer.tsx import  React  from  'react' ; import  {  PriceChart  }  from  './PriceChart' ; import  {  VolumeChart  }  from  './VolumeChart' ; import  {  AssetTable  }  from  './AssetTable' ; import  {  WalletHoldings  }  from  './WalletHoldings' ; import  {  WalletBalance  }  from  './WalletBalance' ; import  {  WalletPnL  }  from  './WalletPnL' ; import  {  SignRequest  }  from  './SignRequest' ; import  {  NftGrid  }  from  './NftGrid' ; import  {  TokenLogo  }  from  './TokenLogo' ; export  function  UIBlockRenderer ({  ui  } :  {  ui :  any  }) {   switch  ( ui . kind ) {     case  'price_chart' :       return  < PriceChart  { ... ui }  /> ;     case  'volume_chart' :       return  < VolumeChart  { ... ui }  /> ;     case  'asset_table' :       return  < AssetTable  { ... ui }  /> ;     case  'wallet_holdings' :       return  < WalletHoldings  { ... ui }  /> ;     case  'wallet_balance' :       return  < WalletBalance  { ... ui }  /> ;     case  'wallet_pnl' :       return  < WalletPnL  { ... ui }  /> ;     case  'sign_request' :       return  < SignRequest  { ... ui }  /> ;     case  'nft_grid' :       return  < NftGrid  { ... ui }  /> ;     case  'token_logo' :       return  < TokenLogo  { ... ui }  /> ;     default :       console . warn ( 'Unknown UI block kind:' ,  ui . kind );       return  null ;   } } 2. Streaming UI Updates Using Fetch API :type  StreamEvent  =  {   event :  'text'  |  'ui'  |  'end'  |  'error' ;   content ?:  string ;   ui ?:  any ;   done ?:  boolean ; }; export  async  function  startChatStream (   message :  string ,   token :  string ,   onEvent :  ( event :  StreamEvent )  =>  void ) {   const  response  =  await  fetch ( '/api/v1/chatbot/chat/stream' , {     method:  'POST' ,     headers:  {       'Content-Type' :  'application/json' ,       'Authorization' :  `Bearer  ${ token } ` ,     },     body:  JSON . stringify ({  message  }),   });   const  reader  =  response . body ?. getReader ();   const  decoder  =  new  TextDecoder ();   while  ( true ) {     const  {  done ,  value  }  =  await  reader . read ();     if  ( done )  break ;     const  chunk  =  decoder . decode ( value );     const  lines  =  chunk . split ( ' \n ' ). filter ( line  =>  line . trim ());     for  ( const  line  of  lines ) {       try  {         const  event  =  JSON . parse ( line );         onEvent ( event );       }  catch  ( e ) {         console . error ( 'Failed to parse event:' ,  line );       }     }   } } 3. Rendering Components Dynamically Complete Chat Component :// components/Chat.tsx import  {  useState ,  useRef ,  useEffect  }  from  'react' ; import  {  startChatStream  }  from  '../lib/stream' ; import  {  UIBlockRenderer  }  from  './UIBlockRenderer' ; type  Message  =  {   role :  'user'  |  'assistant' ;   content :  string ;   ui ?:  any ; }; export  function  Chat () {   const  [ messages ,  setMessages ]  =  useState < Message []>([]);   const  [ input ,  setInput ]  =  useState ( '' );   const  [ streaming ,  setStreaming ]  =  useState ( false );   const  messagesEndRef  =  useRef < HTMLDivElement >( null );   const  scrollToBottom  =  ()  =>  {     messagesEndRef . current ?. scrollIntoView ({  behavior:  'smooth'  });   };   useEffect ( scrollToBottom , [ messages ]);   const  handleSend  =  async  ()  =>  {     if  ( ! input . trim ()  ||  streaming )  return ;     const  userMessage :  Message  =  {  role:  'user' ,  content:  input  };     setMessages ( prev  =>  [ ... prev ,  userMessage ]);     setInput ( '' );     setStreaming ( true );     let  assistantMessage :  Message  =  {  role:  'assistant' ,  content:  ''  };     const  uiBlocks :  any []  =  [];     try  {       await  startChatStream ( input ,  'your-jwt-token' , ( event )  =>  {         if  ( event . event  ===  'text' ) {           assistantMessage . content  +=  event . content ;           setMessages ( prev  =>  [ ... prev . slice ( 0 ,  - 1 ), {  ... assistantMessage  }]);         }  else  if  ( event . event  ===  'ui' ) {           uiBlocks . push ( event . ui );           assistantMessage . ui  =  uiBlocks ;           setMessages ( prev  =>  [ ... prev . slice ( 0 ,  - 1 ), {  ... assistantMessage  }]);         }  else  if  ( event . event  ===  'end' ) {           setStreaming ( false );         }       });       setMessages ( prev  =>  [ ... prev ,  assistantMessage ]);     }  catch  ( error ) {       console . error ( 'Stream error:' ,  error );       setStreaming ( false );     }   };   return  (     < div  className = "chat-container" >       < div  className = "messages" >         { messages . map (( msg ,  idx )  =>  (           < div  key = { idx }  className = { `message  ${ msg . role } ` } >             < div  className = "message-content" > { msg . content } </ div >             { msg . ui  &&  msg . ui . map (( ui :  any ,  uiIdx :  number )  =>  (               < div  key = { uiIdx }  className = "ui-block" >                 < UIBlockRenderer  ui = { ui }  />               </ div >             )) }           </ div >         )) }         < div  ref = { messagesEndRef }  />       </ div >       < div  className = "input-container" >         < input           type = "text"           value = { input }           onChange = { ( e )  =>  setInput ( e . target . value ) }           onKeyPress = { ( e )  =>  e . key  ===  'Enter'  &&  handleSend () }           placeholder = "Ask about prices, portfolios, swaps..."           disabled = { streaming }         />         < button  onClick = { handleSend }  disabled = { streaming  ||  ! input . trim () } >           { streaming  ?  'Streaming...'  :  'Send' }         </ button >       </ div >     </ div >   ); } 4. State Management  React Context
 Zustand Store
// contexts/ChatContext.tsx import  {  createContext ,  useContext ,  useState ,  ReactNode  }  from  'react' ; type  ChatContextType  =  {   messages :  Message [];   addMessage :  ( message :  Message )  =>  void ;   updateLastMessage :  ( updater :  ( msg :  Message )  =>  Message )  =>  void ;   clearMessages :  ()  =>  void ; }; const  ChatContext  =  createContext < ChatContextType  |  null >( null ); export  function  ChatProvider ({  children  } :  {  children :  ReactNode  }) {   const  [ messages ,  setMessages ]  =  useState < Message []>([]);   const  addMessage  =  ( message :  Message )  =>  {     setMessages ( prev  =>  [ ... prev ,  message ]);   };   const  updateLastMessage  =  ( updater :  ( msg :  Message )  =>  Message )  =>  {     setMessages ( prev  =>  {       const  last  =  prev [ prev . length  -  1 ];       return  [ ... prev . slice ( 0 ,  - 1 ),  updater ( last )];     });   };   const  clearMessages  =  ()  =>  setMessages ([]);   return  (     < ChatContext.Provider  value = { {  messages ,  addMessage ,  updateLastMessage ,  clearMessages  } } >       { children }     </ ChatContext.Provider >   ); } export  const  useChat  =  ()  =>  {   const  context  =  useContext ( ChatContext );   if  ( ! context )  throw  new  Error ( 'useChat must be used within ChatProvider' );   return  context ; }; Examples Simple Chart Generation User Query : “Show me ETH price for the last 7 days”Stream Response :// Event 1: Text {   "event" :  "text" ,   "content" :  "Here's the ETH price chart for the last 7 days:" ,   "done" :  false } // Event 2: UI Block {   "event" :  "ui" ,   "ui" : {     "kind" :  "price_chart" ,     "symbol" :  "ETH" ,     "range" :  "7d" ,     "currency" :  "USD" ,     "data" : [       { "t" :  "2024-01-01T00:00:00Z" ,  "price" :  2200 },       { "t" :  "2024-01-02T00:00:00Z" ,  "price" :  2250 },       { "t" :  "2024-01-03T00:00:00Z" ,  "price" :  2180 },       { "t" :  "2024-01-04T00:00:00Z" ,  "price" :  2300 },       { "t" :  "2024-01-05T00:00:00Z" ,  "price" :  2350 },       { "t" :  "2024-01-06T00:00:00Z" ,  "price" :  2280 },       { "t" :  "2024-01-07T00:00:00Z" ,  "price" :  2400 }     ]   },   "done" :  false } // Event 3: End {   "event" :  "end" ,   "done" :  true } Rendered Output : A complete line chart showing ETH price trend.Complex Dashboard User Query : “Show me a full analysis of my wallet 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb”Stream Response : Multiple UI blocks in sequence:
Wallet Balance Card : Total portfolio valueHoldings Table : Breakdown by assetPnL Chart : Performance over timeRecent Transactions : Last 10 transactions 
// The chat component automatically renders each UI block as it arrives < div  className = "wallet-dashboard" >   < WalletBalance  { ... balanceUI }  />   < WalletHoldings  { ... holdingsUI }  />   < WalletPnL  { ... pnlUI }  />   < AssetTable  { ... transactionsUI }  /> </ div > Interactive Swap Interface User Query : “Swap 1 ETH for USDC”Stream Response :{   "event" :  "ui" ,   "ui" : {     "kind" :  "sign_request" ,     "chain" :  "ethereum" ,     "wallet_address" :  "0x742d35..." ,     "title" :  "Swap 1 ETH → USDC" ,     "payload" : {       "transaction" : {         "to" :  "0x..." ,         "data" :  "0x..." ,         "value" :  "1000000000000000000" ,         "gasLimit" :  "200000"       }     },     "disclaimer" :  "Review all transaction details carefully before signing."   } } Rendered : Interactive swap form with sign button that connects to user’s wallet.Real-Time Price Updates User Query : “Monitor BTC and ETH prices”Implementation with Continuous Streaming :function  PriceMonitor () {   const  [ prices ,  setPrices ]  =  useState < Record < string ,  number >>({});   useEffect (()  =>  {     const  cleanup  =  startChatStream (       "Monitor BTC and ETH prices" ,       token ,       ( event )  =>  {         if  ( event . event  ===  'ui'  &&  event . ui . kind  ===  'price_chart' ) {           const  latestPrice  =  event . ui . data [ event . ui . data . length  -  1 ]. price ;           setPrices ( prev  =>  ({             ... prev ,             [event.ui.symbol]:  latestPrice ,           }));         }       }     );     return  cleanup ;   }, []);   return  (     < div  className = "price-monitor" >       { Object . entries ( prices ). map (([ symbol ,  price ])  =>  (         < div  key = { symbol }  className = "price-card" >           < span  className = "symbol" > { symbol } </ span >           < span  className = "price" > $ { price . toFixed ( 2 ) } </ span >         </ div >       )) }     </ div >   ); } Best Practices  Component Memoization
 Lazy Loading
 Virtual Scrolling
import  {  memo  }  from  'react' ; export  const  PriceChart  =  memo (({  symbol ,  data  } :  PriceChartProps )  =>  {   // Component implementation }, ( prevProps ,  nextProps )  =>  {   // Custom comparison: only re-render if data actually changed   return  prevProps . symbol  ===  nextProps . symbol  &&          JSON . stringify ( prevProps . data )  ===  JSON . stringify ( nextProps . data ); }); Error Handling export  function  UIBlockRenderer ({  ui  } :  {  ui :  any  }) {   try  {     // Validate UI block structure     if  ( ! ui  ||  ! ui . kind ) {       console . error ( 'Invalid UI block:' ,  ui );       return  < ErrorBoundary > Invalid component data </ ErrorBoundary > ;     }     // Render based on kind     switch  ( ui . kind ) {       case  'price_chart' :         if  ( ! ui . data  ||  ! Array . isArray ( ui . data )) {           return  < ErrorBoundary > Invalid chart data </ ErrorBoundary > ;         }         return  < PriceChart  { ... ui }  /> ;       case  'sign_request' :         if  ( ! ui . chain  ||  ! ui . wallet_address  ||  ! ui . payload ) {           return  < ErrorBoundary > Incomplete sign request </ ErrorBoundary > ;         }         return  < SignRequest  { ... ui }  /> ;       default :         console . warn ( 'Unknown UI kind:' ,  ui . kind );         return  null ;     }   }  catch  ( error ) {     console . error ( 'UI rendering error:' ,  error );     return  < ErrorBoundary > Failed to render component </ ErrorBoundary > ;   } } // Error Boundary Component class  ErrorBoundary  extends  React . Component <   {  children :  React . ReactNode  },   {  hasError :  boolean  } > {   state  =  {  hasError:  false  };   static  getDerivedStateFromError () {     return  {  hasError:  true  };   }   render () {     if  ( this . state . hasError ) {       return  < div  className = "error" > Something went wrong rendering this component. </ div > ;     }     return  this . props . children ;   } } Accessibility export  function  PriceChart ({  symbol ,  data  } :  PriceChartProps ) {   return  (     < div       className = "price-chart"       role = "img"       aria-label = { `Price chart for  ${ symbol } ` }     >       < h3  id = { `chart- ${ symbol } ` } > { symbol }  Price </ h3 >       < LineChart         width = { 600 }         height = { 300 }         data = { data }         aria-labelledby = { `chart- ${ symbol } ` }       >         < XAxis  dataKey = "t"  />         < YAxis  />         < Tooltip  />         < Line           type = "monotone"           dataKey = "price"           stroke = "#8884d8"           aria-label = "Price line"         />       </ LineChart >       { /* Provide text alternative for screen readers */ }       < div  className = "sr-only" >         { symbol }  price data:  { data . map ( d  =>  ` ${ d . t } : $ ${ d . price } ` ). join ( ', ' ) }       </ div >     </ div >   ); } Mobile Responsiveness import  {  useState ,  useEffect  }  from  'react' ; function  useIsMobile () {   const  [ isMobile ,  setIsMobile ]  =  useState ( false );   useEffect (()  =>  {     const  checkMobile  =  ()  =>  setIsMobile ( window . innerWidth  <  768 );     checkMobile ();     window . addEventListener ( 'resize' ,  checkMobile );     return  ()  =>  window . removeEventListener ( 'resize' ,  checkMobile );   }, []);   return  isMobile ; } export  function  PriceChart ({  symbol ,  data  } :  PriceChartProps ) {   const  isMobile  =  useIsMobile ();   return  (     < div  className = "price-chart" >       < LineChart         width = { isMobile  ?  350  :  600 }         height = { isMobile  ?  200  :  300 }         data = { data }       >         < XAxis           dataKey = "t"           angle = { isMobile  ?  - 45  :  0 }           textAnchor = { isMobile  ?  'end'  :  'middle' }         />         < YAxis  />         < Tooltip  />         < Line  type = "monotone"  dataKey = "price"  stroke = "#8884d8"  />       </ LineChart >     </ div >   ); } /* Responsive styles */ .price-chart  {   width :  100 % ;   max-width :  600 px ;   margin :  1 rem  auto ; } @media  ( max-width :  768 px ) {   .price-chart  {     max-width :  100 % ;     padding :  0  1 rem ;   }   .chart-container  {     overflow-x :  auto ;   } } .asset-table  {   overflow-x :  auto ; } .asset-table  table  {   min-width :  600 px ; } @media  ( max-width :  768 px ) {   .asset-table  table  {     min-width :  100 % ;     font-size :  0.875 rem ;   } } Security Considerations Critical Security Rules for Sign Requests :
Never Auto-Execute : Always require explicit user confirmationDisplay Full Details : Show all transaction parameters in plain languageValidate Addresses : Verify address format and checksumNetwork Matching : Ensure connected wallet matches requested chainThrottle Requests : Debounce consecutive sign_request blocks to prevent spamWarn on High Values : Alert users for transactions above configured thresholdsAudit Logging : Log all signature requests and outcomes Example Security Implementation :export  function  SignRequest ({  chain ,  wallet_address ,  payload ,  disclaimer  } :  SignRequestProps ) {   const  [ userConfirmed ,  setUserConfirmed ]  =  useState ( false );   const  [ addressValidated ,  setAddressValidated ]  =  useState ( false );   useEffect (()  =>  {     // Validate address format     const  isValid  =  chain  ===  'ethereum'       ?  ethers . isAddress ( wallet_address )       :  validateSolanaAddress ( wallet_address );     setAddressValidated ( isValid );   }, [ chain ,  wallet_address ]);   const  handleSign  =  async  ()  =>  {     if  ( ! userConfirmed  ||  ! addressValidated ) {       alert ( 'Please confirm all details before signing' );       return ;     }     // Additional checks     if  ( payload . transaction ?. value ) {       const  valueInEth  =  ethers . formatEther ( payload . transaction . value );       if  ( parseFloat ( valueInEth )  >  10 ) {         const  confirmed  =  confirm ( `Warning: High value transaction ( ${ valueInEth }  ETH). Proceed?` );         if  ( ! confirmed )  return ;       }     }     // Proceed with signing...   };   return  (     < div  className = "sign-request" >       { ! addressValidated  &&  (         < div  className = "error" > Invalid address format </ div >       ) }       < label >         < input           type = "checkbox"           checked = { userConfirmed }           onChange = { ( e )  =>  setUserConfirmed ( e . target . checked ) }         />         I have reviewed all details and wish to proceed       </ label >       { disclaimer  &&  < div  className = "disclaimer" > { disclaimer } </ div > }       < button         onClick = { handleSign }         disabled = { ! userConfirmed  ||  ! addressValidated }       >         Sign & Execute       </ button >     </ div >   ); } TypeScript Types For type safety, generate TypeScript types from the backend schemas: 
// types/ui.ts export  type  UIBlock  =   |  PriceChartUI   |  VolumeChartUI   |  AssetTableUI   |  WalletHoldingsUI   |  WalletBalanceUI   |  WalletPnLUI   |  SignRequestUI   |  NftGridUI   |  TokenLogoUI ; export  interface  PriceChartUI  {   kind :  'price_chart' ;   title ?:  string ;   symbol ?:  string ;   pair ?:  string ;   currency ?:  string ;   range ?:  string ;   data :  Array <{  t :  string ;  price :  number  }>; } export  interface  VolumeChartUI  {   kind :  'volume_chart' ;   title ?:  string ;   symbol ?:  string ;   pair ?:  string ;   data :  Array <{  t :  string ;  volume :  number  }>; } export  interface  AssetTableUI  {   kind :  'asset_table' ;   title ?:  string ;   rows :  Array <{     symbol :  string ;     name ?:  string ;     price ?:  number ;     change_24h_pct ?:  number ;     volume_24h ?:  number ;     logo_url ?:  string ;   }>; } export  interface  WalletHoldingsUI  {   kind :  'wallet_holdings' ;   wallet_address :  string ;   chain ?:  string ;   rows :  Array <{     symbol :  string ;     amount :  number ;     usd_value ?:  number ;     logo_url ?:  string ;   }>; } export  interface  WalletBalanceUI  {   kind :  'wallet_balance' ;   wallet_address :  string ;   chain ?:  string ;   total_usd ?:  number ;   breakdown :  Array <{     symbol :  string ;     amount :  number ;     usd_value ?:  number ;     logo_url ?:  string ;   }>; } export  interface  WalletPnLUI  {   kind :  'wallet_pnl' ;   wallet_address :  string ;   period ?:  string ;   pnl_usd ?:  number ;   pnl_pct ?:  number ;   timeseries ?:  Array <{     t :  string ;     pnl_usd :  number ;   }>; } export  interface  SignRequestUI  {   kind :  'sign_request' ;   chain :  string ;   wallet_address :  string ;   title ?:  string ;   message ?:  string ;   payload :  any ;   disclaimer ?:  string ; } export  interface  NftGridUI  {   kind :  'nft_grid' ;   title ?:  string ;   items :  Array <{     token_id ?:  string ;     name ?:  string ;     collection ?:  string ;     image_url ?:  string ;     permalink ?:  string ;   }>; } export  interface  TokenLogoUI  {   kind :  'token_logo' ;   symbol :  string ;   logo_url :  string ;   name ?:  string ;   size ?:  'sm'  |  'md'  |  'lg' ; } Next Steps Need Help?  Join our developer community or check out the example React implementation in examples/frontend/react/ in the Nex-T1 repository.