New Feature: Selection Tags

Check out our new Selection Tags Editor Element!

Selection Tags let site visitors choose from a set of options, each displayed as a tag. They provide a neat and compact alternative to checkbox groups and radio buttons.

You can find Selection Tags in the Add Panel under User Input after you create a data collection or turn on Dev Mode.

What can you do with Selection Tags?

  • Data users can let visitors specify their preferences when filling out a form

  • Corvid users can let visitors filter dynamic content based on categories or keywords

Be sure to:

FAQ

Q: Can I add a checkmark icon to selected tags?
A: At the moment icons are not supported. However, you can achieve this effect by adding a ✓ Unicode character with Corvid. Check out this example .

Q: Can I use Selection Tags for single-selection?
A: Almost, but not quite. You can achieve similar behavior with Corvid, but it will suffer from accessibility issues (namely, keyboard navigation and screen-reader will not behave as expected). We are aware of the demand for this feature, which is likely to comprise our first follow-up release.

Q: Can I limit the number of tags a visitor can select?
A: Yes, with Corvid. See this example .

Code for these examples is provided in the comments below. If you found them helpful, please click the Heart button to let us know.

That’s it. We’re here for questions, and of course, feedback is much appreciated!
Enjoy :slight_smile:

1 Like

Code for the checkmark icon example:

var ORIG_OPTIONS = null;
$w.onReady(function () {
    let tags = $w('#selectionTags1');
    ORIG_OPTIONS = tags.options;
    // Some options may be selected by default. Decorate them.
    decorateSelectedTags(tags, prefixTextWithCheckmark);
});

function prefixTextWithCheckmark(text) { return '✓ ' + text; }

function decorateOption(option, decorator) {
    return {
        label: decorator(option.label),
        value: option.value
    };
}

function decorateSelectedTags(tags, decorator) {
    // Decorate labels of selected tags.
    // Instead of keeping track of which selected options we have already decorated, simply go over the ORIGINAL options and decorate the selected ones.
    tags.options = ORIG_OPTIONS.map(option => {
        return tags.value.includes(option.value) ? decorateOption(option, decorator): option;
    });
}

export function selectionTags1_change(event) {
    decorateSelectedTags(event.target, prefixTextWithCheckmark);
}

Code for single-selection example:

var prevSelectedValue = null;

$w.onReady(function () {
    let tags = $w('#selectionTags1');
    if (tags.value.length === 1) {
        prevSelectedValue = tags.value[0];
    } else if (tags.value.length > 1) {
        // If multiple tags are selected by default, deselect all of them (since there's no good reason to prefer one of them over the others).
        tags.value = [];
    }
});

export function selectionTags1_change(event) {
    // Prevent deselecting the only selected tag. Radio buttons do not allow it so tags shouldn't either.
    if (!event.target.value || event.target.value.length === 0) {
        // Re-apply the previously selected tag.
        event.target.value = [prevSelectedValue];
        // Replace the previously selected tag with the newly selected one.
    } else {
        // Note: Array.filter() was added in ES7. Only works in some browsers.
        event.target.value = event.target.value.filter(x => x !== prevSelectedValue);
        prevSelectedValue = event.target.value[0];
    }
}

Code for limited number of selected tags example:

const MAX_SELECTED_TAGS = 3;
var prevSelectedValues = null;

$w.onReady(function () {
    let tags = $w('#selectionTags1');
    if (tags.value.length > MAX_SELECTED_TAGS) {
        // If more than MAX tags are selected by default, deselect all of them (since there's no good reason to prefer one of them over the others).
        tags.value = [];
    }
    prevSelectedValues = tags.value.slice();
});

export function selectionTags1_change(event) {
    if (event.target.value.length > MAX_SELECTED_TAGS) {
        // Re-apply the previous selection.
        event.target.value = prevSelectedValues.slice();
    } else {
        prevSelectedValues = event.target.value.slice();
    }
}

This is a great update release with regards to the API resources, but I keep wondering, what is great about having the option to be able to select items and submit the selected items to a database without having the option to display tags submitted to the database with the same selection Tags element. At least Wix should give us an element (similar to the selection tags) that can be dedicated to displaying tag items from a database. I have tried to, but if anyone was able to connect the Selection Tags element to display tags from a database field using the “options” or any of the other Corvid API functions, please advise or share. Thanks

Thank you very much for providing this valuable feedback!

One of the features planned for a follow-up release is reading the choices from a Tags field.

We are considering two alternatives (may eventually decide to support just one of the two, or both):

  1. Read the choices from a dataset
  2. Connect the value to a Reference field with multiple items, and then the choices are taken from the referenced collection

Sharing the specs for both options, with notes for our internal usage and everything :wink:
Please tell us what you think.

BTW, the Dropdown Editor Element already supports similar connection options, so you can try it out to get a clearer impression.

HTH,
Eyal

My code isn’t connecting my dataset to the page,

import wixData from 'wix-data';
const collectionName = 'radSites';
const fieldToFilterByInCollection = 'tags';
$w.onReady(function () {
setRepeatedItemsInRepeater()
loadDataToRepeater()
$w('#tags').onChange((event) => {
const selectedTags = $w('#tags').value
loadDataToRepeater(selectedTags)
})
});
function loadDataToRepeater(selectedCategories = []) {
let dataQuery = wixData.query(collectionName)
if (selectedCategories.length > 0) {
dataQuery = dataQuery.hasAll(fieldToFilterByInCollection, selectedCategories)
}

dataQuery
.find()
.then(results => {
const itemsReadyForRepeater = results.items
$w('#radSites').data = itemsReadyForRepeater;
const isRepeaterEmpty = itemsReadyForRepeater.length === 0
if (isRepeaterEmpty) {
$w('#noResultsFound').show()
} else {
$w('#noResultsFound').hide()
}
})
}
function setRepeatedItemsInRepeater() {
$w('#radSites').onItemReady(($item, itemData) => {
$item('#image9').src = itemData.image;
$item('#text44').tooltip = itemData.title;
$item('#text46').text = itemData.description;
})
}
export function tags_change(event) {
//Add your code for this event here:
}

I changed the IDs to the corresponding names for my page components & datasets, and while nothing is underlined I have red dots on all the lines that use the $w selector.

Is there something I need to download to make that work? Any idea what’s wrong?

Great to have the new selection tags user input.

I have a page with a Selection Tag element that I would like to connect via WIX Editor code to a database called BusinessCategories, field called Tags (It is currently a text field but I can change it to tags if required).

The repeater is connected via code from this example to my LocalBusinesses database that is working fine.

Thanking you in advance
Sylvia

I think might have an extra space before r in radSites.
const collectionName = ‘radSites’;
Other than that you code is the same as the example.

@eyalc Fantastic.

  1. It would be great if we can use the selection tags element to display items from tags field in the database. This means without having to input those items in the selection tag element. Just like how a text input element can be used to both send data to the database and display text data from the database.

I think the above will really help us solve a lot of problems.

Can this feature be made to run an inclusive filter? As in, union rather than intersection, returning e.g. entries with tagA or tagB or both, rather than just those with both.

Many thanks.

@eyalc I want to access the value of the tag which is selected when it is clicked or on the mouseIn event. Is that supported in selection Tags?
I want to build a functionality where on hovering over the tag, there is description which is shown explaining the option (which I was planning to the store in the value attribute of the tag).

Hey @shadab211 ,
This is a good point you’re raising. I believe right now the mouse-in event does not pass the information of which tag is being hovered. This is the same issue CheckboxGroup and RadioButtons have, and is indeed worth fixing for all of them.
The onClick event does not pass this information either.
However, if you are OK with showing the description on click (how will this work actually?) then you can listen on the onChange event.
The onChange event lets you know what tags are selected taking the latest click into effect. Just access event.target.value or event.target.selectedIndices.
In order to tell which tag is the one most recently clicked, you need to keep track of the previous selection (update it every time onChange is fired) and check the difference between the current selection and the previous one.
Please let me know if you wish to get a code sample that does this.
It would be easier if the onChange event came with the previous selection instead of you having to keep track of it yourself. I’ll discuss it with the Corvid team.
BTW, onChange is also fired when the visitor navigates the tags with keyboard and presses ‘Space’. This will also display the description you’re trying to show.

Using the values to hold the description sounds like room for trouble to me.
Care to share more about your use case? Maybe there are better alternatives.

Thanks!

@lhoarnold Sorry for taking so long to reply.
Sure, take a look at this example website . Try selection ‘Transportation’ and ‘Maritime’ and see the different result for the inclusive page vs. the exclusive one.

Here’s the code for the inclusive page:

import wixData from 'wix-data';

function createFilterThatMatchesAnyKeyword(selectedKeywords) {
    return (selectedKeywords && selectedKeywords.length > 0) ?
        // Filter content that fits any of the the selected keywords.
        wixData.filter().hasSome('keywords', selectedKeywords) :
        // When no keywords are selected, do not filter any content.
        wixData.filter();
}

export function keywords_change(event) {
    let selectedKeywords = event.target.value;
    let filter = createFilterThatMatchesAnyKeyword(selectedKeywords);
    $w('#portfolioDataset').setFilter(filter);
}

And here’s the code for the exclusive page:

import wixData from 'wix-data';

function createFilterThatMatchesAllKeywords(selectedKeywords) {
    return (selectedKeywords && selectedKeywords.length > 0) ?
        // Filter content that fits all the selected keywords.
        wixData.filter().hasAll('keywords', selectedKeywords) :
        // When no keywords are selected, do not filter any content.
        wixData.filter();
}
export function keywords_change(event) {
    let selectedKeywords = event.target.value;
    let filter = createFilterThatMatchesAllKeywords(selectedKeywords);
    $w('#portfolioDataset').setFilter(filter);
}

Mind that the only meaningful change is wixData.filter().hasSome being replaced with wixData.filter().hasAll.

HTH

@lhoarnold Forgot something important :slight_smile:
Code above relies on the Repeater being connected to a dataset (named ‘#portfolioDataset’). Unlike the documented example , here I simply update the filter on this dataset.

@granteverist looking at the code I don’t see where the issue is.
Were you able to solve this? If not, could you please share the link to your website so that I could take a better look at what’s going on?
Thanks

Thanks @eyalc for the quick response! :slight_smile:
My use case is to create a tool where the user selects a certain number of keywords from a larger collection. My total data collection is about 300+ words and their descriptions. I had created this using a repeater but the moment I put in my complete data, the repeater sort of crashed ( which was very disappointing ).
So while searching for alternatives, I came across selection Tags but it doesn’t give much flexibility in terms of behavior.
I agree that holding description in values is potential trouble and should be avoided.
I’ll probably look for some design alternatives to see how this can be accommodated.

Thanks for sharing.
Yes, values are expected to be used as unique identifiers of the options (choices).

The main reasons we support values in addition to labels are:

  1. To allow you to translate the labels on Multilingual websites (this is why labels cannot always be relied upon to be unique identifiers when referred to in code).
  2. To allow you to re-order the options without having to change your code (this is why indices cannot always be relied upon to be unique identifiers when referred to in code).

What do you mean by “the repeater sort of crashed”? How did this look/behave?

The page did not load at all (unresponsive) when I was fetching my data from the database. I later moved the data to a local array. Now the page loaded after almost a minute. Even after loading the performance of the repeater was very slow. If I click on a container, it took a 5-10 seconds to reflect the click ( onClick event on the container ).
Had posted regarding this at:
https://www.wix.com/corvid/forum/community-discussion/repeater-with-huge-data-gets-stuck/

Sorry @1425club66601 , still not sure about what exactly you are trying to achieve.
Would you like to read the choices from the database, write the tags visitors select into this database, or both?