Data Attributes System¶
Overview¶
Balancy automatically processes HTML elements with special data attributes, providing declarative functionality without writing JavaScript code. This system allows you to configure UI behavior directly in HTML.
Key Benefits:
- No JavaScript required for common patterns
- Visual editors can configure behavior
- Automatic backend integration
- Type-safe data binding
Button Actions¶
Add data-button-action to make any element interactive and connected to Balancy backend.
Basic Usage¶
<!-- Buy offer button -->
<button data-button-action="101" data-button-params='{"productId": "coin_pack_1"}'>
Buy Coins
</button>
<!-- Buy group offer -->
<button data-button-action="102" data-index="0">
Buy Special Pack
</button>
<!-- Claim battle pass reward -->
<button data-button-action="104" data-index="2">
Claim Reward
</button>
<!-- Close window -->
<button data-button-action="200">
Close
</button>
Available Attributes¶
| Attribute | Type | Description |
|---|---|---|
data-button-action |
number | Action ID from balancy.RequestAction enum |
data-button-params |
JSON string | Additional parameters for the action |
data-index |
number | Index parameter for array-based actions |
Common Actions¶
| Action ID | Name | Parameters | Description |
|---|---|---|---|
101 |
BuyOffer | productId |
Purchase an offer |
102 |
BuyGroupOffer | index |
Purchase from group offer |
103 |
BuyShopSlot | slotId |
Purchase shop slot |
104 |
BattlePassClaim | lineId, index |
Claim battle pass reward |
200 |
CloseWindow | - | Close the view |
Button Events¶
Buttons dispatch events when actions complete:
balancyButtonResponse Event:
button.addEventListener('balancyButtonResponse', (event) => {
const { actionId, result, success, senderId } = event.detail;
if (success) {
console.log(`Action ${actionId} succeeded:`, result);
// Show success message
} else {
console.log(`Action ${actionId} failed:`, event.detail.error);
// Show error message
}
});
balancyButtonError Event:
button.addEventListener('balancyButtonError', (event) => {
const { actionId, error, paramsAttr } = event.detail;
console.error(`Button error: ${error}`);
});
Example: Purchase Flow¶
<!-- Button with custom styling and action -->
<button id="buy-btn"
class="buy-button"
data-button-action="101"
data-button-params='{"productId": "starter_pack"}'>
Buy Starter Pack
</button>
<script>
const buyBtn = document.getElementById('buy-btn');
buyBtn.addEventListener('balancyButtonResponse', (event) => {
if (event.detail.success) {
showSuccessAnimation();
updatePlayerCurrency();
} else {
showErrorDialog(event.detail.error);
}
});
</script>
Dynamic Text Updates¶
Elements with data-text-type="dynamic" automatically update with backend data.
Basic Dynamic Text¶
<!-- Show offer price -->
<span data-text-type="dynamic"
data-info-type="1"
data-text-format="{price} USD">
</span>
<!-- Show time remaining -->
<span data-text-type="dynamic"
data-info-type="3"
data-text-format="Time left: {time}">
</span>
Available Attributes¶
| Attribute | Type | Description |
|---|---|---|
data-text-type |
"dynamic" | Marks element for dynamic updates |
data-info-type |
number | Type of information to fetch (InfoType enum) |
data-text-format |
string | Template string with {placeholder} syntax |
data-custom |
string | Custom parameter for InfoType.Custom |
data-product-id |
string | Product ID for price queries |
data-index |
number | Index for group offers |
InfoType Values¶
| Value | Name | Description | Example |
|---|---|---|---|
1 |
OfferPrice | Display offer price | "$4.99" |
2 |
OfferGroupPrice | Display group offer price | "100 Gems" |
3 |
TimeLeft | Display time remaining (auto-formatted) | "2h 15m" |
4 |
OwnerLocalizedKey | Format with owner data, use as localization key | Localized text |
5 |
OwnerCustom | Format with owner data directly | "25% OFF" |
9 |
CustomPrice | Display custom price | Custom format |
10 |
Custom | Display custom data | Any custom data |
Advanced InfoTypes¶
OwnerLocalizedKey (InfoType 4)¶
Formats template using window.balancyViewOwner data, then uses result as a localization key.
When to use: Displaying localized text from backend data.
<!-- If owner has gameOffer.name = "OFFER_SUPER_PACK_NAME" -->
<span data-text-type="dynamic"
data-info-type="4"
data-text-format="{gameOffer.name}">
</span>
<!-- Displays: Localized text for key "OFFER_SUPER_PACK_NAME" -->
Automatic Document Resolution:
If gameOffer is null but unnyIdGameOffer exists:
1. System fetches document using balancy.getDocumentValue(unnyIdGameOffer)
2. Continues with path (name in this case)
3. Uses result as localization key
Owner Data Example:
window.balancyViewOwner = {
instanceId: "f09ab140-3752-4593-98e3-48a31046",
gameOffer: null, // Will be auto-resolved
unnyIdGameOffer: "1188", // Used for resolution
discount: 25,
priceUSD: 4.99
};
OwnerCustom (InfoType 5)¶
Formats template using window.balancyViewOwner data directly for display.
When to use: Displaying raw values (numbers, custom strings, calculations).
<!-- Direct formatting with owner data -->
<span data-text-type="dynamic"
data-info-type="5"
data-text-format="{discount}% OFF - ${priceUSD}">
</span>
<!-- Displays: "25% OFF - $4.99" -->
Complex Formatting:
<span data-text-type="dynamic"
data-info-type="5"
data-text-format="Buy {quantity} for ${price} (Save {savings}%)">
</span>
Usage Guidelines¶
✓ Correct Pattern:
<!-- For localized title (use InfoType 4) -->
<h1 data-text-type="dynamic"
data-info-type="4"
data-text-format="{gameOffer.name}">
</h1>
<!-- For price and discount (use InfoType 5) -->
<span data-text-type="dynamic"
data-info-type="5"
data-text-format="{discount}% OFF">
</span>
<span data-text-type="dynamic"
data-info-type="5"
data-text-format="${priceUSD}">
</span>
✗ Incorrect Pattern:
<!-- DON'T do this - gameOffer.name is a localization key, not display text -->
<span data-text-type="dynamic"
data-info-type="5"
data-text-format="{gameOffer.name} - {discount}% OFF">
</span>
Key Points:
- InfoType 4: Use when displaying localized text (e.g.,
gameOffer.name) - InfoType 5: Use for raw data (numbers, prices, custom strings)
- Don't mix: Avoid combining localization keys with raw data in InfoType 5
Automatic Localization¶
Elements with data-text-type="localized" automatically get localized from the Localization system.
<h1 data-text-type="localized" data-localization-key="welcome_title">
Welcome
</h1>
<button data-text-type="localized" data-localization-key="buy_button">
Buy Now
</button>
<p data-text-type="localized" data-localization-key="tutorial.step_1">
Click here to start
</p>
Process:
1. Element is found with data-text-type="localized"
2. Localization key is read from data-localization-key
3. Text is fetched using balancy.getLocalizedText(key)
4. Element's textContent is updated
Automatic Image Loading¶
Elements with data-image-id automatically load images from Balancy resources.
IMG Elements¶
<img data-image-id="icon_123" alt="Reward Icon">
<img data-image-id="player_avatar" alt="Player">
Background Images¶
<div data-image-id="background_456" class="hero-section"></div>
<div data-image-id="panel_bg" class="panel"></div>
9-Slice Images¶
<div data-image-id="button_bg"
data-use-nineslice="true"
slice-top="20"
slice-right="20"
slice-bottom="20"
slice-left="20">
</div>
Process:
1. Element is found with data-image-id
2. Image URL is fetched using balancy.getImageUrl(id)
3. For IMG elements: src is set
4. For other elements: background-image or border-image-source is set
Custom Font Injection¶
Elements with font data attributes automatically load custom fonts.
<div data-font-id="font_789"
data-font-name="CustomFont"
class="styled-text">
This text uses a custom font
</div>
<h1 data-font-id="title_font"
data-font-name="TitleFont">
Game Title
</h1>
Attributes:
data-font-id: Font asset ID in Balancydata-font-name: Font family name to use in CSS
Element Identification¶
Use data-id for JavaScript element queries (alternative to HTML id).
<div data-id="player-info">
<span data-id="player-name">Player Name</span>
<span data-id="player-level">Level 1</span>
<img data-id="player-avatar" src="avatar.png">
</div>
JavaScript:
// Find by data-id
const playerInfo = balancy.findDomElement('player-info');
const nameElement = balancy.findDomElement('player-name', playerInfo);
const levelElement = balancy.findDomElement('player-level', playerInfo);
Benefits:
- Namespace separation from HTML IDs
- Easier to query within scopes
- Framework convention
Prefab Placeholders¶
Use data-prefab-id to mark where prefabs should be instantiated.
<!-- Placeholder for player card prefab -->
<div data-prefab-id="player-card"
data-guid="..."
class="card-container">
</div>
<!-- Placeholder for shop prefab -->
<div data-prefab-id="shop"
data-guid="...">
</div>
Process:
1. Placeholder found with data-prefab-id
2. Prefab loaded by ID
3. Prefab children moved to placeholder
4. data-prefab-id attribute removed (prevents reprocessing)
5. Nested prefabs processed recursively
Learn More: Prefabs & Components
Script Components¶
Use data-script-id to attach script components to elements (new component system).
<div id="health-bar">
<div data-script-id="HealthBar"
data-guid="abc123..."
data-script-params='{"maxHealth":{"type":"number","value":100}}'
style="display:none">
</div>
<div class="health-bar-fill"></div>
</div>
Attributes:
data-script-id: Script class namedata-guid: Unique identifierdata-script-params: Serialized parameters (JSON)style="display:none": Hidden by default
Learn More: Prefabs & Components
Combining Attributes¶
You can combine multiple data attributes on a single element:
<button data-id="buy-button"
data-button-action="101"
data-button-params='{"productId": "gems_100"}'
data-text-type="dynamic"
data-info-type="1"
data-text-format="Buy for {price}">
Buy Gems
</button>
This button:
- Has identifier buy-button for JavaScript queries
- Triggers purchase action (101)
- Displays dynamic price text
- All configured declaratively in HTML!
Best Practices¶
1. Use Semantic Attributes¶
<!-- ✓ Good: Clear, semantic -->
<button data-button-action="101"
data-button-params='{"productId": "starter_pack"}'>
Buy Starter Pack
</button>
<!-- ✗ Avoid: Magic numbers without context -->
<button data-action="101" data-params='{"p": "sp"}'>
Buy
</button>
2. Format JSON Correctly¶
<!-- ✓ Good: Valid JSON with double quotes -->
<div data-button-params='{"productId": "coins", "amount": 100}'></div>
<!-- ✗ Avoid: Invalid JSON -->
<div data-button-params="{productId: coins, amount: 100}"></div>
3. Use InfoType Appropriately¶
<!-- ✓ Good: InfoType 4 for localized keys -->
<h1 data-text-type="dynamic"
data-info-type="4"
data-text-format="{gameOffer.name}">
</h1>
<!-- ✓ Good: InfoType 5 for raw data -->
<span data-text-type="dynamic"
data-info-type="5"
data-text-format="${price}">
</span>
<!-- ✗ Avoid: Mixing in InfoType 5 -->
<span data-text-type="dynamic"
data-info-type="5"
data-text-format="{gameOffer.name} - ${price}">
</span>
4. Provide Fallback Content¶
<!-- ✓ Good: Fallback text before dynamic update -->
<span data-text-type="dynamic"
data-info-type="3"
data-text-format="Time left: {time}">
Loading...
</span>
<!-- ✗ Avoid: Empty, causes layout shift -->
<span data-text-type="dynamic"
data-info-type="3"
data-text-format="Time left: {time}">
</span>
Troubleshooting¶
Dynamic Text Not Updating¶
Problem: Text element stays with fallback content.
Solutions:
- Check
data-info-typeis valid number - Verify
window.balancyViewOwnerhas required data - Look for JavaScript errors in console
- Ensure
data-text-formatplaceholders match data keys
Button Not Responding¶
Problem: Button click does nothing.
Solutions:
- Verify
data-button-actionis valid action ID - Check
data-button-paramsis valid JSON - Look for
balancyButtonErrorevents - Ensure button is not disabled
Images Not Loading¶
Problem: Image element shows broken icon or no image.
Solutions:
- Verify image ID exists in Balancy assets
- Check
data-image-idattribute is correct - Look for 404 errors in Network tab
- Ensure images are deployed
Fonts Not Applied¶
Problem: Custom font not showing.
Solutions:
- Verify font is uploaded to Balancy
- Check
data-font-idanddata-font-namematch - Ensure font is added to view in UI Builder
- Look for font loading errors in console
Next Steps¶
- Learn Events System for lifecycle events
- Check Balancy API for programmatic access
- See Prefabs & Components for script components
- Explore Templates for ready-to-use examples