tag-list
Building a tag-list from standard HTML elements is a bit of a nightmare.
<tosi-tag-list> allows you to display an editable or read-only tag list (represented either
as a comma-delimited string or an array of strings).
<label style="position: absolute; right: 10px; top: 10px; display: block">
<input type="checkbox" class="disable-toggle">
<b>Disable All</b>
</label>
<label>
<b>Display Only</b>
<tosi-tag-list
value="this,that,,the-other"
></tosi-tag-list>
</label>
<tosi-tag-list
class="compact"
value="this,that,,the-other"
></tosi-tag-list>
<br>
<label>
<b>Editable</b>
<tosi-tag-list
class="editable-tag-list"
value="belongs,also belongs,has\, comma,custom"
editable
available-tags="belongs,also belongs,has\, comma,not initially chosen"
></tosi-tag-list>
</label>
<br>
<b>Text-Entry</b>
<tosi-tag-list
value="this,that,the-other,not,enough,space"
editable
text-entry
available-tags="tomasina,dick,,harriet"
></tosi-tag-list>
.preview .compact {
--spacing: 8px;
--font-size: 12px;
--line-height: 18px;
}
.preview label {
display: flex;
flex-direction: column;
align-items: flex-start;
}
preview.addEventListener('change', (event) => {
if (event.target.matches('tosi-tag-list')) {
console.log(event.target, event.target.value)
}
}, true)
preview.querySelector('.disable-toggle').addEventListener('change', (event) => {
const tagLists = Array.from(preview.querySelectorAll('tosi-tag-list'))
for(const tagList of tagLists) {
tagList.disabled = event.target.checked
}
})
const tagLists = preview.querySelectorAll('tosi-tag-list')
test('tag-lists render', () => {
expect(tagLists.length).toBe(4)
})
test('first tag-list has correct tags', () => {
expect(tagLists[0].tags.length).toBe(3)
expect(tagLists[0].tags).toContain('this')
})
test('editable tag-list has editable attribute', () => {
expect(tagLists[2].editable).toBe(true)
})
test('a comma inside a tag survives the value round-trip', () => {
const tl = document.createElement('tosi-tag-list')
tl.tags = ['New York, NY', 'Boston']
// the literal comma is escaped in `value` so it is not a delimiter
expect(tl.value).toBe('New York\\, NY,Boston')
expect(tl.tags.length).toBe(2)
expect(tl.tags).toContain('New York, NY')
})
test('an escaped comma in a value string parses as one tag', () => {
const tl = document.createElement('tosi-tag-list')
tl.value = 'New York\\, NY,Boston'
expect(tl.tags.length).toBe(2)
expect(tl.tags).toContain('New York, NY')
})
Properties
value: string | string[]
A comma-delimited list of tags. A tag that itself contains a comma must
escape it as \, — e.g. value="New York\, NY,Boston" is two tags. The
tags accessor handles this escaping for you in both directions.
tags: string[]
popSelectMenu: () => void
This is the method called when the user clicks the menu button. By default is displays a pick list of tags, but if you wish to customize the behavior, just replace this method.
A read-only property giving the value as an array.
available-tags: string | string[]
A list of tags that will be displayed in the popup menu by default. The popup menu
will always display custom tags (allowing their removal). As with value, a
comma inside a tag must be escaped as \, when set via the attribute string.
editable: boolean
Allows the tag list to be modified via menu and removing tags.
text-entry: boolean
If editable, an input field is provided for entering tags directly.
placeholder: string = 'enter tags'
Placeholder shown on input field.