Tag
Tags represent a set of interactive keywords that help to label, organize, and categorize objects.
This is the API of the Tag component, all HTML attributes and JS properties correspond to the table below, you can use them to customize how your tag looks.
Passing complex data via HTML attributes
Any properties that aren't Functions
can be given value via HTML attributes, simply by writing `data-ts.${propertyName}=${encodedValue}`
.
When passing complex data structures as HTML attributes, you need to JSON.stringify()
the value and then pass it to encodeURIComponent
to get a string that can be safely used as an attribute.
We supply ts.ui.encode()
as a helper function that does just this.
Now that you know how to pass complex data to components, it's time to go through the different kinds of things the tag can do.
Value-only
Any non-string
passed to data
will be converted into a Map
, using non-unique keys
will result in unreliable behavior!
Values are simple descriptors, with lighter font weights and lowercase characters. To render, use a Map
-like Array
with only a value
and a falsy key
.
It's also possible to set data
(and all other attributes) later, through the JS API.
<script>
ts.ui.ready(() => {
ts.ui.get('#tag-roll20', tag => {
tag.data = new Map([
[null, 'Roll a d20']
]);
});
});
</script>
<figure
id="tag-roll20"
data-ts="Tag">
</figure>
Key-Value
If you need a key
with a value
attached to it, use the Map
-like Array
structure like before, but with a key
and a value
this time.
<script>
const data = ts.ui.encode(
[
['Area of Origin', 'The Sword Coast']
]
);
</script>
<figure
data-ts="Tag"
data-ts.data="%5B%5B%22Area%20of%20Origin%22%2C%22The%20Sword%20Coast%22%5D%5D">
</figure>
Key with multiple values
You can have a single key
with multiple values
, just make the value
part of the Map
-like Array
an Array
.
<script>
const data = ts.ui.encode(
[
['The Teeming Hive of Evil', ['Skullport', 'Port of Shadows']]
]
);
</script>
<figure
data-ts="Tag"
data-ts.data="%5B%5B%22The%20Teeming%20Hive%20of%20Evil%22%2C%5B%22Skullport%22%2C%22Port%20of%20Shadows%22%5D%5D%5D">
</figure>
Multiple keys with single value
Of course you could flip it around and use several keys
for a single value
.
<script>
const data = ts.ui.encode(
[
[['Facial Tentacles', 'Potent Psionics'], 'Mind Flayer']
]
);
</script>
<figure
data-ts="Tag"
data-ts.data="%5B%5B%5B%22Facial%20Tentacles%22%2C%22Potent%20Psionics%22%5D%2C%22Mind%20Flayer%22%5D%5D">
</figure>
Multiple keys with multiple values
It comes naturally that you can have several keys
together with several values
.
<script>
const data = ts.ui.encode(
[
[['Magic-user', 'Undead'], ['Lich', 'Vampire']]
]
);
</script>
<figure
data-ts="Tag"
data-ts.data="%5B%5B%5B%22Magic-user%22%2C%22Undead%22%5D%2C%5B%22Lich%22%2C%22Vampire%22%5D%5D%5D">
</figure>
Multiple sets of key-values
If you want to have several key
/value
sets in a single tag, just have more entries in your Map
-like Array
.
<script>
const data = ts.ui.encode(
[
['Acererak'],
['Alignment', ['Lawful', 'Evil']],
['Hobbies', 'Building Dungeons'],
]
);
</script>
<figure
data-ts="Tag"
data-ts.data="%5B%5B%22Acererak%22%5D%2C%5B%22Alignment%22%2C%5B%22Lawful%22%2C%22Evil%22%5D%5D%2C%5B%22Hobbies%22%2C%22Building%20Dungeons%22%5D%5D">
</figure>
Clickable look & click handler
If you want to make your tag look like it can be clicked, once you've initialized your tag, set the onclick
handler.
<script>
const data = ts.ui.encode(
[
['Vision', ['Blindsight', 'Truesight', 'Darkvision']]
]
);
ts.ui.ready(() => {
ts.ui.get('#tag-clickable', tag => {
tag.onclick = () => {
ts.ui.Notification.success('Do you see?');
};
});
});
</script>
<figure
id="tag-clickable"
data-ts="Tag"
data-ts.data="%5B%5B%22Vision%22%2C%5B%22Blindsight%22%2C%22Truesight%22%2C%22Darkvision%22%5D%5D%5D">
</figure>
You can use your own click handler if you'd like.
Make sure to set data-ts.clickable="true"
, otherwise your tag won't look like it's clickable.
<script>
const data = ts.ui.encode(
[
['Vision', ['Blindsight', 'Truesight', 'Darkvision']]
]
);
ts.ui.ready(() => {
ts.ui.get('#tag-clickable-ownhandler', tag => {
tag.element.addEventListener('click', e => {
ts.ui.Notification.success('Do you see?');
});
});
});
</script>
<figure
id="tag-clickable-ownhandler"
data-ts="Tag"
data-ts.clickable="true"
data-ts.data="%5B%5B%22Vision%22%2C%5B%22Blindsight%22%2C%22Truesight%22%2C%22Darkvision%22%5D%5D%5D">
</figure>
Delete button & delete handler
If you want to be able to remove a tag, once you've initialized the tag, set the ondelete
handler. This will create a DEL
element as the last child of the tag.
When the DEL
element is clicked, the tag will be removed from the DOM after a setTimeout
. Don't try to read anything through the DOM at this point.
<script>
const data = ts.ui.encode(
[
['Languages', ['Sylvan', 'Common', 'Draconic', 'Giant']]
]
);
ts.ui.ready(() => {
ts.ui.get('#tag-deletable', tag => {
tag.ondelete = () => {
ts.ui.Notification.info('Tag disintegrated!');
}
});
});
</script>
<figure
id="tag-deletable"
data-ts="Tag"
data-ts.data="%5B%5B%22Languages%22%2C%5B%22Sylvan%22%2C%22Common%22%2C%22Draconic%22%2C%22Giant%22%5D%5D%5D">
</figure>
Just like with click
, you can use your own click handler for deletion if you'd like.
You have to remember that only react when the user clicks on the DEL
element by checking for e.target.localName
.
<script>
const data = ts.ui.encode(
[
['Languages', ['Sylvan', 'Common', 'Draconic', 'Giant']]
]
);
ts.ui.ready(() => {
ts.ui.get('#tag-deletable-ownhandler', tag => {
tag.element.addEventListener('click', e => {
if (e.target.localName === 'del') {
ts.ui.Notification.info('Tag disintegrated!');
}
});
});
});
</script>
<figure
id="tag-deletable-ownhandler"
data-ts="Tag"
data-ts.deletable="true"
data-ts.data="%5B%5B%22Languages%22%2C%5B%22Sylvan%22%2C%22Common%22%2C%22Draconic%22%2C%22Giant%22%5D%5D%5D">
</figure>
Click & delete
In case you want to handle clicks
and have a delete
button on the same tag, you can do that the same way as above.
<script>
const data = ts.ui.encode(
[
['Beholder', 'Xanathar']
]
);
ts.ui.ready(() => {
ts.ui.get('#tag-delete-click', tag => {
tag.onclick = () => {
ts.ui.Notification.info('Don\'t poke the beholder!');
};
tag.ondelete = () => {
ts.ui.Notification.warning('I hope you know what you\'re doing...');
}
});
});
</script>
<figure
id="tag-delete-click"
data-ts="Tag"
data-ts.data="%5B%5B%22Beholder%22%2C%22Xanathar%22%5D%5D">
</figure>
You can always handle your own clicks
if that's what you're into.
You still have to remember that only handle the delete
click
when the user clicks on the DEL
element by checking for e.target.localName
.
<script>
const data = ts.ui.encode(
[
['Beholder', 'Xanathar']
]
);
ts.ui.ready(() => {
ts.ui.get('#tag-delete-click-ownhandler', tag => {
tag.element.addEventListener('click', e => {
if (e.target.localName === 'del') {
ts.ui.Notification.warning('I hope you know what you\'re doing...');
} else {
ts.ui.Notification.info('Don\'t poke the beholder!');
}
});
});
});
</script>
<figure
id="tag-delete-click-ownhandler"
data-ts="Tag"
data-ts.clickable="true"
data-ts.deletable="true"
data-ts.data="%5B%5B%22Beholder%22%2C%22Xanathar%22%5D%5D">
</figure>
Locked look
If you want to lock down a tag, use data-ts.locked="true"
.
A locked tag will have its DEL
button hidden and all click
-related styling deactivated.
<script>
const data = ts.ui.encode(
[
['Dungeon', 'Hidden Shrine of Tamoachan']
]
);
</script>
<figure
data-ts="Tag"
data-ts.locked="true"
data-ts.data="%5B%5B%22Dungeon%22%2C%22Hidden%20Shrine%20of%20Tamoachan%22%5D%5D">
</figure>