Skip to content
YutaiDocs
GET /v1/statusGet API key

Web SDK / React

Embed with React

The SDK's React components render Yutai's six elements on a page built with React, each component's props named for the attributes its element reads. Install the package, import the component you need, and the samples below show the result.

View as .md

The script

Yutai serves the SDK's script at the address below: a page built with React does not load it, because the components' import registers the same elements before the first render.

The script is served today.

Embed code
<script src="https://app.yutai.com/sdk/v1/yutai-sdk-web.min.js"></script>

The components

Install the distributor SDK package (@yutai/sdk-web) with your package manager, then import the components you need from its react door (@yutai/sdk-web/react). The import registers the same elements the script line above registers, before the first render: a React page never writes a define of its own, and it needs no second copy of the SDK.

Each component renders its element, never a second card. The props you pass are written on the element as its own attributes, so the element reads its facts on connect the way it does on a page without React.

The components cover all six of the SDK's elements: the credential card, the tier badge, the benefits list, the benefits module and the two Connect presses. The Connect button opens the hosted consent screen and the manage component opens the manage screen; the Connect page carries both. The benefits module's two doors, the wallets and the answer, stay on the benefits module's own page; its component takes the claimWallets prop, the page's wallets beside their sign calls, and its onClaimed prop hears the module's own claimed event.

The props

Each component's attribute props are its element's attributes under their camel case names, listed below in the element's own order. A prop you pass is written on the element under the attribute's own name; a prop you leave out writes no attribute, so the element reads it as missing. The attributes' full words and the tokens each element takes stay on the element pages: the credential card, the benefits list, the benefits module and the tier badge.

The credential card's props

tier
Required. The tier the card carries, one of Tier 1, Tier 2 or Tier 3.
status
Required. The verification status the card shows: minted or revoked.
tenureDays
With the tenure set, or alone on a Tier 3 card: the days the credential has been held, like "145". The tenure comes as one set: pass tenureDays, tenureNextTier and tenureProgress together, or none of them.
tenureNextTier
With the tenure set: the tier the tenure is moving toward, one of the tiers above the card's own tier. Not given on a Tier 3 card, the top tier.
tenureProgress
With the tenure set: the progress toward the next tier, a percentage of 0 through 100, like "62.5". Not given on a Tier 3 card, the top tier.
tenureProgressDecimals
Optional. The scale the percentage shows: a whole number of digits, like "1". Not given on a Tier 3 card.

The credential card also takes onError, a prop the element's attributes do not carry: called once per refusal with the element's tag and the plain sentence that says what to fix. The credential card page lists the refusals it tells.

The tier badge's props

tier
Required on the tier draw. The tier the badge carries, one of Tier 1, Tier 2 or Tier 3. A badge names a tier or an instrument, never both.
tenureDays
Optional, with tier on the tier draw: the days the credential has been held, like "145", the same figure the card's tenureDays carries. Absent, the badge draws the tier's word alone.
isin
Required on the instrument draw. The ISIN of the instrument the badge marks: the badge asks the distributor API which benefits the instrument carries, through the client your page connected with connectDistributorApi, and paints the mark that says benefits exist at the company. The tenureDays prop never rides the instrument draw.
answer
Optional on the instrument draw. The availability read's own answer for the instrument, as JSON text: the badge draws the row it carries instead of asking anyone, so a page whose read happened elsewhere hands every badge the row the read answered it with, and no key reaches the browser. Write a badge only where your read answered; a company the read answers nothing for wears no badge.

The tier badge also takes onError, a prop the element's attributes do not carry: called once per refusal with the element's tag and the plain sentence that says what to fix. The tier badge page lists the refusals it tells.

The benefits list's props

benefits
Required. The benefit rows as an array, at most 500 rows, each in the shape the benefits list page documents. The wrapper serialises the array to the one benefits attribute the element reads, so a page passes its rows and never a string it builds itself.
ownerCustomer
Optional. True when your server's Connect outcome says the holder owns the company and shops with it. Until then, a row marked needsConnect draws locked with the Connect button beneath it.
connectSessionUrl
Optional. The Connect session's hosted address your server's create answered. A row behind Connect carries the button that opens it, and onConnect hears the answer.

The benefits list adds three props the element's attributes do not carry: onClaim, called with the benefit's id once per claim event the element dispatches, onConnect, called with the session and its status when the Connect press answers, and onError, called once per refusal with the element's tag and the plain sentence that says what to fix. The claim stays your own action: the component writes nothing itself, and the benefits list page carries the event's words and the refusals it tells.

The benefits module's props

wallets
Optional. The wallet addresses to read, as an array, each once. The wrapper serialises the array to the one wallets attribute, and the element asks through the client your page connected with connectDistributorApi. Pass the wallets or the answer, never both.
answer
Optional. The eligibility answer as JSON text: the element draws the tokens and benefits the answer carries without asking anyone, so a page whose read ran on its own server hands the answer over and no key reaches the browser. Pass the answer or the wallets, never both.
highlightIsin
Optional. The ISIN of the security whose rows stand lit, the link between the element and an answer drawn beside it: the page sets the ISIN a reader points at or focuses, and the element reports its own rows through the yutai-isin-highlight event so the two can light each other.
readOnly
Optional. True draws the module read-only: it shows the answer's holdings as a table with no claim sheet, for a page such as a docs example. The same mode is the element's read-only attribute.

The benefits module takes three props of its own: pass the wallets or the answer, never both, and hand the claim sheet the page's wallets beside their sign calls with claimWallets. It also takes the two event props the element's attributes do not carry: onClaimed, called with the claim's id and the benefit's id once per claim the module grants, and onHighlight, called with the security's ISIN when a row is pointed at or focused and with null when the reader leaves it. The component writes nothing itself, and the benefits module page carries the element's own words.

The samples

Each sample below renders through the components above, and its code block pastes whole into a React page: the component imports from the SDK's package, the sample's data stands written out in the block, and on your page you pass the values your holder carries.

The credential card sample

Sample figures: a simulated holder, not a real credential.
The credential card's code
"use client";

import { CredentialCard } from "@yutai/sdk-web/react";

const card = {
  "tier": "Tier 1",
  "status": "minted",
  "tenureDays": "145",
  "tenureNextTier": "Tier 2",
  "tenureProgress": "62.5"
} as const;

export function CredentialCardSample() {
  return (
    <CredentialCard
      tier={card.tier}
      status={card.status}
      tenureDays={card.tenureDays}
      tenureNextTier={card.tenureNextTier}
      tenureProgress={card.tenureProgress}
    />
  );
}

The benefits list sample

Sample rows: a simulated holder's benefits, not a real holder's.
The benefits list's code
"use client";

import { BenefitsList } from "@yutai/sdk-web/react";

const benefits = [
  {
    "benefitId": "bft_01H8Z2N9P4QX7K3M5A0V8D9T2W",
    "name": "Season voucher",
    "type": "VOUCHER",
    "delivery": "CODE",
    "state": "eligible",
    "sourceMode": "SIMULATED"
  },
  {
    "benefitId": "bft_01H8Z2N9P4QX7K3M5A0V8D9T2X",
    "name": "Lounge access",
    "type": "ACCESS",
    "delivery": "VENUE_REDEMPTION",
    "state": "locked",
    "lockedReason": "This benefit opens once the wallet keeps 15 SGH for 30 days.",
    "sourceMode": "SIMULATED"
  },
  {
    "benefitId": "bft_01H8Z2N9P4QX7K3M5A0V8D9T2Y",
    "name": "Welcome points",
    "type": "POINTS",
    "delivery": "POINTS_CREDIT",
    "state": "claimed",
    "sourceMode": "SIMULATED"
  }
] as const;

export function BenefitsListSample() {
  return <BenefitsList benefits={benefits} />;
}

The benefits module sample

Sample figures: a simulated holder's tokens and benefits, not a real holder's.
The benefits module's code
"use client";

import { BenefitsModule } from "@yutai/sdk-web/react";

const answer = {
  "wallets": [
    {
      "wallet": "0xabc0000000000000000000000000000000000001",
      "read": true,
      "sourceMode": "SIMULATED",
      "tokens": [
        {
          "issuer": null,
          "security": {
            "name": "Sample Global Holdings",
            "isin": "US0000000009",
            "ticker": "SGH"
          },
          "symbol": "SGHon",
          "chainName": "chiliz-testnet",
          "wrapper": "Sample token programme",
          "chain": "eip155:88880",
          "shares": "15",
          "daysHeld": 452,
          "tier": "Tier 2",
          "credentialTier": "Tier 2",
          "benefits": [
            {
              "benefitId": "bft_01K4V9QG000000000000000001",
              "name": "Sample lounge access",
              "type": "ACCESS",
              "delivery": "VENUE_REDEMPTION",
              "state": "eligible",
              "illustrative": true,
              "scope": "base",
              "funder": "YUTAI"
            },
            {
              "benefitId": "bft_01K4V9QG000000000000000002",
              "name": "Sample welcome points",
              "type": "POINTS",
              "delivery": "POINTS_CREDIT",
              "state": "locked",
              "lockedReason": "This benefit opens once the wallet keeps 15 SGH for 30 days.",
              "illustrative": true,
              "scope": "base",
              "funder": "YUTAI"
            }
          ]
        }
      ]
    },
    {
      "wallet": "0xdef0000000000000000000000000000000000002",
      "read": false,
      "sourceMode": "SIMULATED",
      "unreadReason": "Yutai has not read this wallet yet."
    }
  ]
} as const;

export function BenefitsModuleSample() {
  return <BenefitsModule answer={JSON.stringify(answer)} />;
}

The tier badge sample

Sample figures: a simulated holder, not a real credential.
The tier badge's code
"use client";

import { TierBadge, type TierBadgeProps } from "@yutai/sdk-web/react";

const badges: TierBadgeProps[] = [
  {
    "tier": "Tier 1",
    "tenureDays": "145"
  },
  {
    "tier": "Tier 2",
    "tenureDays": "58"
  },
  {
    "tier": "Tier 3"
  }
];

export function TierBadgeSamples() {
  return (
    <>
      {badges.map((badge) => (
        <TierBadge key={badge.tier} tier={badge.tier} tenureDays={badge.tenureDays} />
      ))}
    </>
  );
}