Embed the benefits module
The benefits module, yutai-benefits-module, draws the whole token picture on one page: one row per token of every wallet its answer carries, each naming the security, the issuer, the wrapper, the chain, the holding and the tier, with the benefits that holding reaches beneath it. Its facts arrive as one of two doors: the wallets attribute, whose ask rides the page's connected client, or the answer attribute, which the module draws without asking anyone; the highlight-isin attribute links the draw to an answer a page shows beside it, lighting the rows of the security it names. Set read-only to draw the shared holdings table the Yutai app carries, one row per company, with the Ready to claim chip linking to the app.
The script
Yutai serves the SDK's script at the address below: the script loads once, then the module asks through the page's connected client, so call connectDistributorApi with the distributor's key before the module loads.
The script is served today.
<script src="https://app.yutai.com/sdk/v1/yutai-sdk-web.min.js"></script>
<yutai-benefits-module wallets='["0xabc0000000000000000000000000000000000001"]'></yutai-benefits-module>The sample
The sample draws the real element here through the answer door: the module carries the answer Yutai's eligibility read carries, as JSON text, and draws it without asking anyone. One wallet of the sample was read, one Yutai has not read yet, so the sample asks for nothing and carries no key.
The attributes
The module takes the answer or the wallets, never both: a page that names both doors is refused before anything paints. Each attribute carries one of the two doors, under the name the element reads. The read-only attribute switches the drawing to the shared holdings table, with no claim press.
wallets- The wallet addresses as JSON text, at most 20 addresses in one read. The module asks what the wallets reach through the connected client your page made with
connectDistributorApi, the one keyed door per page: the module carries no key of its own and fetches nothing on its own path. The refusals section quotes an example of the shape the addresses take. answer- The eligibility answer as JSON text, the answer Yutai's eligibility read carries: the module draws it instead of asking, so a page whose read happens on its server hands the answer over and no key reaches the browser.
highlight-isin- Optional. The ISIN of the security whose rows stand lit, for a page that draws the API answer beside the module: set it as the reader points at or focuses a company, and the module lights every row of that security. Each row fires
yutai-isin-highlightwith its own ISIN, and again with null when the reader leaves it, so the answer's blocks can light in step. read-only- Optional, true or false. True draws the shared holdings table the Yutai app carries: one row per company, the shares combined by company, the filter presses in place inside the element, and the Ready to claim chip linking to the Yutai app in a new tab, where a wallet proof can stand. No claim press or claim sheet draws in this mode. Leave it off to keep the module's claimable cards and its claim sheet.
Styling parts
Each piece of the module is a named part inside its shadow root, so your page can restyle one without touching the others. The module carries six parts, and a name it does not carry matches nothing.
token-row- Each token's facts line: the security, its issuer, the wrapper, the chain, the holding and the tenure days, drawn in one row.
badge- The tier chip in a token's facts line, the level that holding reaches.
benefits-row- Each benefit card beneath a token: eligible with its claim press, locked with the sentence that says why, claimed or redeemed.
benefits-claim- The claim press on an eligible benefit card. A press opens the module's own claim sheet.
claim-sheet- The claim sheet's panel, the layer that names the benefit and asks for the wallet's signature.
claim-sheet-confirm- The confirm press inside the claim sheet, the one that signs the challenge and records the claim.
yutai-benefits-module::part(token-row) { background: teal; }
yutai-benefits-module::part(claim-sheet) { border-color: navy; }The tokens
Set the tokens you want on the element itself, the way the member template does: a value the element carries beats its own binding.
--accent- The primary action colour.
--accent-foreground- The text colour that sits on the primary action colour.
--focus- The colour focus rings wear.
--link- The colour a link wears.
--radius- The corners the element rounds with, 0 to 0.75rem.
--yutai-font-sans- The font stack the element's text renders in.
--background- The page background around the element, from the approved neutral list.
The claim
A press on an eligible card's claim button opens the claim sheet: the sheet names the benefit, asks Yutai for the one message the holder's wallet signs, and its confirm step draws the safety sentence that message itself carries beside one wallet line each, so a page that hands more than one wallet claims with the one the holder picks. The press signs the challenge once with that wallet's own call and records the claim on that proof, and the sheet draws the claimed word, with the code the answer carried beside it and, on the first grant, a link that opens the holder's own redemption page: the claim's own address the answer carried, never one the sheet composes. A replay of a claim already granted answers the same code and never a link, and a refusal draws neither. The wallets the sheet proves with are your page's own, handed in as the property below: the sheet reads the property at press time, so a page that hands it after the module drew is read the same way a page that handed it before the first paint is.
claimWallets- The wallets the claim sheet proves with, as a JavaScript property on the element, never an attribute: an array of entries, each carrying the wallet's address beside its own
signMessagecall, the call that answers the signature. No key rides an entry; the sign call is the page's own. A press without the property, or with a malformed entry, opens the sheet with the one sentence that names it, and nothing is sent. A module that carries no wallets reads:
A first entry that is not a wallet with its sign call reads, naming the entry's position:The benefits module carries no claimWallets wallets to prove the claim with. Set the module's claimWallets property to the page's wallets beside their sign calls, then press Claim again.
The claimWallets property carries an entry that is not a wallet with its sign call at position 1. Each entry carries the wallet's address and its own signMessage call.
A granted answer tells your page the claim stands through one event; a refused one fires nothing.
yutai-claimed- Fired once for each granted answer, from the element itself, bubbling and crossing the element's shadow root, so a listener on your document hears it wherever the element sits. An answer marked
alreadyClaimedis granted too, so it fires the event; a refused answer fires nothing. The module's press opens the sheet instead of dispatching the benefits list's own yutai-claim event; the list keeps its own. detail.claimId- The id of the claim the sheet's ask recorded.
detail.benefitId- The pressed benefit's id, exactly as the drawn answer carried it.
document.addEventListener("yutai-claimed", (event) => {
const { claimId, benefitId } = event.detail;
// The claim stands on Yutai's record: update your own records from the two ids.
});The refusals
The module never paints input it cannot read. A refusal happens before anything renders, so the module keeps its last good paint, and it reaches your page as one yutai-error event, its detail carrying the module's tag and one plain sentence.
For a page that names both doors, the sentence is:
The benefits module has both an answer and a wallets attribute. Set the answer or the wallets, never both.
For a page that names neither, the sentence is:
The benefits module has no wallets attribute. Set wallets to the wallet addresses as JSON, like ["0xabc0000000000000000000000000000000000001"].