The Situation
In SharePoint 2010, when you create a lookup field that allows for multiple selections, you end up with a very non-standard html widget that includes 2 boxes for moving “possible” values to “selected” values. Like so:

That’s all well and good if you have short values and a long list of them. But, if you happen to have long values and a short list of them, SharePoint’s UI choice is less than spectacular. As you can see in the image, most of the values are hidden in the select box. Marc Anderson has a function in his popular SpServices library to resize the select boxes to show the complete value. But, that’s not always preferable – as that can make your page very, very wide.
The Solution
Wouldn’t it be nice if you could just make a checkbox interface instead of the multi-select interface? Why, yes, yes it would. And now you can. There are a few moving parts here. I’ll try to break it down.
First, we need a way to select and unselect choices in the multi-select UI. It’s not as easy as just highlighting a value and using jQuery to “click” the add or remove button. Believe me, I tried that. Happily, I found someone else that grappled with this issue, and he got me most of the way there. I had to tweak a couple of things, because I had multiple multi-select fields on a single form, and because I know my users well enough to know that they’ll go crazy checking and unchecking things. So, here are my add choice and remove choice functions.
Add Choice
function addChoice(text, columnName) { // let's get the id from the column name var thisID = $("[title='" + columnName + " possible values']").prop('id'); thisID = thisID.substr(0, thisID.indexOf('_SelectCandidate')); selector = "[id$=" + thisID + "_MultiLookupPicker]"; $("[title='" + columnName + " possible values'] option").each(function () { if ($(this).text() == text) { $(this).appendTo($("[title='" + columnName + " selected values']")); var multilookupPickerVal = $(selector).val(); if ($(selector).val() == undefined || $(selector).val().length == 0) { $(selector).val($(this).val() + "|t" + $(this).text()); } else { $(selector).val(multilookupPickerVal + "|t" + $(this).val() + "|t" + $(this).text()); } } }); }
Remove Choice
function removeChoice(text, columnName) { // let's get the id from the column name var thisID = $("[title='" + columnName + " selected values']").prop('id'); thisID = thisID.substr(0, thisID.indexOf('_SelectResult')); selector = "[id$=" + thisID + "_MultiLookupPicker]"; // loop through the selected options $("[title='" + columnName + " selected values'] option").each(function () { if ($(this).text() == text) { $(this).appendTo($("[title='" + columnName + " possible values']")); var multilookupPickerVal = $(selector).val(); // call the internal function which creates a clean array out of the weird string var splitValue = GipSplit(multilookupPickerVal); // set the 2 array nodes we want to remove var valToRemove = $(this).val(); var textToRemove = $(this).text(); // Kill the value and text in the array splitValue = jQuery.grep(splitValue, function(value) { return value != valToRemove; }); splitValue = jQuery.grep(splitValue, function(value) { return value != textToRemove; }); var newValue = ''; // loop through the cleaned up array and rebuild the selector value for (var i = 0; i < splitValue.length; i++) { if (newValue.length == 0) { newValue = splitValue[i]; } else { newValue = newValue + '|t' + splitValue[i]; } } // end for loop // set the new value to the selector $(selector).val(newValue); } }); }
Next, we need a function to draw the checkboxes to the screen. I wanted to make this as simple as possible, so this same function draws the checkboxes, hides the old UI, and attaches the remove and add choice functions to the click events of the checkboxes.
Draw Checkboxes
// function used to draw the checkboxes instead of a multi-select lookup function drawCheckboxes(columnName) { // remove spaces from columnName var divName = columnName.split(' ').join('') + 'Checkboxes'; // find the parent td, hide the span, clear the div $('div[id="' + divName + '"]').remove(); $("[title='" + columnName + " possible values']").closest('span').after('<div id="' + divName + '">New div</div>'); $("[title='" + columnName + " possible values']").closest('span').hide(); var thisDiv = $('div[id="' + divName + '"]').html(''); // loop through all the possible options and draw the checkboxes $("[title='" + columnName + " possible values'] option").each(function () { var thisText = $(this).text(); var thisVal = $(this).val() var thisSnippet = "<input type='checkbox' name='" + columnName + "' value='" + thisText + "' id='" + columnName + "Checkbox" + thisVal + "'/><label for='" + columnName + "Checkbox" + thisVal + "'>" + thisText + "</label><br/>"; thisDiv.append(thisSnippet); }); // loop through all the selected options and draw the checkboxes $("[title='" + columnName + " selected values'] option").each(function () { var thisText = $(this).text(); var thisVal = $(this).val() var thisSnippet = "<input type='checkbox' name='" + columnName + "' value='" + thisText + "' id='" + columnName + "Checkbox" + thisVal + "'/><label for='" + columnName + "Checkbox" + thisVal + "'>" + thisText + "</label><br/>"; thisDiv.append(thisSnippet); }); // Loop through the checklist for outcome statement lookup var boxes = $('input[name="' + columnName + '"]'); boxes.each(function(index) { $(this).click(function() { // get the label if( $(this).is(':checked')){ addChoice($(this).val(), columnName); } else { removeChoice($(this).val(), columnName); } }); }); // End loop } //end draw checkboxes
The basic solution
Great – now we have functions that will draw checkboxes and add and remove choices when the checkboxes are clicked. What do you do with it? First put all your scripts together in a text file and upload your text file to your site. (Note, there is one line you’ll need to edit in this text file.) (I typically use the site assets library.) On your page with your data form web part, you’ll need to include a content editor web part and link to your text file. Run your page, and voila – checkboxes! (Note that in this image, I’ve shown both interfaces.)

Of course, around here, we’re integrating this with SPServices, to filter the multi-select. For that, you need a few more steps. First, you’ll need a copy of SPServices in your site, and you’ll need to include a reference to SPServices in your text file. Next, you’ll need to make a function that will work as a call-back to the SPServices.SPFilterDropdown or SPCascadeDropdowns function. Functions passed as callbacks can’t have parameters (at least, I haven’t figured out how to do it). So, you’ll need a wrapper function for drawCheckboxes that passes in the column you want. This is convenient because you can also do other stuff at the same time, if need be. Here’s my example, using a filter.
Wrapper Function
// need this function to pass a parameter-free function to the complete function of the dropdown filter function drawProgramAreaCheckboxes() { drawCheckboxes("Collaborators Program Area"); } //end drawProgramAreaCheckboxes
Calling the SpServices Filter function with callback
//Filter and draw checkboxes for program areas $().SPServices.SPFilterDropdown({ relationshipList: "Program Area", relationshipListColumn: "Title", relationshipListSortColumn: "ID", columnName: "Collaborators Program Area", CAMLQuery: " 1", completefunc: drawProgramAreaCheckboxes, debug: true }); //End program areas
Here’s the complete file for using checkboxes with SpServices. Note, there are multiple parts you’ll need to customize in here.
Editing Forms
Now that we have adding forms figured out, we need to do something about editing. It’s essentially the same, but you need to set the checkboxes that require setting. Again, for this, we’re using SPServices, and we need a few more function calls.
Step one – helper functions to set checkbox values
We need a couple of helper functions to set the checkboxes. The first sets a checkbox’s selected property to true based on the value of the checkbox.
function checkByValue(value) { $(":checkbox").filter(function() { return this.value == value; }).prop("checked", "true"); }
The second takes in a string as returned by spSpervices GetListItems for multi-select fields and the column name and loops through the string, setting each checkbox. The string returned is a series of ID’s and values, separated by semi-colons and hash tags. So, we’ll split the string on the ;# combo, and then check only when we have a value, not a number. Caveat – if your values ARE numbers, this won’t work for you, and you’d need to do check every other value, instead of the textual values.
function setMultiSelectValueCheckboxes(inString, column) { var outString = inString.split(";#"); $.each(outString, function( index, value ) { if (isNaN(value)) { checkByValue(value); } }); } // end set MultiSelectValueCheckboxes
Step two – get the ID from the query string.
SpServices has a helper function that lets you get parameters from the query string. SharePoint always passes an ID parameter to edit forms. So, you just need to grab it, like so:
// This function from SPServices gets all of the Query String parameters var queryStringVals = $().SPServices.SPGetQueryString(); var effortID = queryStringVals.ID;
Step three – build the checkboxes
Just like in the add scenario, you’ll need to build your checkboxes. You want to build them before you try to check them, or this won’t work. For brevity, you can refer to the completed text file for this section, since it’s no different than the add form.
Step four- use GetListItems to get the thing you’re editing
My test list is called “Educational Effort.” Here I’m passing in a CAML query to get just the item we’re editing. I’ve returned more viewfields than you’d really need. But, you get the idea. If we have a successful status, we then set the value of the checkboxes, using our helper function from above.
// Get the related effort $().SPServices({ operation: "GetListItems", async: true, listName: "Educational Effort", CAMLQuery: "" + effortID + "", CAMLViewFields: "", completefunc: function (xData, Status) { if (Status == 'success') { $(xData.responseXML).SPFilterNode("z:row").each(function() { // get outcome statement and program area values var outcomeStatementLookup = $(this).attr("ows_OutcomeStatementLookup"); var collaboratorsProgramArea = $(this).attr("ows_CollaboratorsProgramArea"); // set checkboxes setMultiSelectValueCheckboxes(outcomeStatementLookup, 'Outcome Statement Lookup'); setMultiSelectValueCheckboxes(collaboratorsProgramArea , 'Collaborators Program Area'); }); // end each function } //end if status = success. } // end complete function }); // end spservices // End get the related effort
And, voila – automatically checked checkboxes.

Here’s the complete file for an edit form. Again, note that you’ll need to customize for your environment.
As usual, feel free to point out places where this could be optimized, tweaked, etc. I’ve testing in IE 10, Chrome and Firefox, and it seems to be working for me.
I must say, that is a much nicer user experience – and a better use of screen space – than the ridiculous way SharePoint handles multi-selects. Glad you were able to get it working!
Is it possible to use this also with already cascaded dropdowns? I’ve already implemented the cascaded dropdowns from the SPServices but now want to display additional fields from the list, so that the users have a better impression what they actually select (something like the SPDisplayRelatedInfo, which unfortunately doesn’t support multi-select).
This solution sounds good, but in the DOM I only have the IDs and not the actual value. Is this somehow possible to realize?
I’m not sure. I’ve not tried to do it with a cascaded dropdown. I have done with an already filtered dropdown (via spFilterDropDown), and you just have to run it as the complete function of the filter. So, perhaps a similar approach with a cascaded dropdown would work?
Excellent idea! I had a go with changing the multi select to a Select2 (http://ivaynberg.github.io/select2/). Ended up having to change from lookup to “single line of text” to get it working.
How Would I Implement the Cascading drop down for multi select dropdown
You would need to run the draw check boxes script as the complete function of the spservices cascade call.
I’m new at this, so sorry if I’m being dim… I got this working fine for the new item form, but the edit item form is not coming up with selected values checked.
I don’t understand how the column parameter passed to setMultiSelectValueCheckboxes(inString, column) is getting used. I feel I’m missing something about how this is working.
That you for this. I’m new at this, and this was the boost I needed to get this done and I learned a lot over the last few days. There are a couple of changes I made in my version that I think improve it…
1. In function drawCheckboxes, in the second loop (through all the _selected_ options), add the “checked” attribute to the html for thisSnippet. Now you no longer need setMultiSelectValueCheckboxes and checkByValue to check the boxes on the page.
2. Your drawCheckBoxes function reorders the checkboxes, always putting the checked boxes at the end. I prefer my checkboxes to be consistent. I modified the drawCheckboxes code in the following way:
a. Add this line before the two loops:
var ckBox= [];
b. In each of the two loops, replace “thisDiv.append(thisSnippet);” with:
ckBox.push(thisSnippet);
c. After the second loop, add the following code:
ckBox.sort();
for (index=0; index < ckBox.length; ++index) {
thisDiv.append(ckBox[index]);
}
This sorts the snippets by value, since the previous text in the snippet is exactly the same for all checkboxes. Make sure the "checked" attribute from 1 above is after the value (I put it as the last attribute in the input tag).
Here's the entire replacement for the 2 loops in my version:
var ckBox= [];
// loop through all the possible options and draw the checkboxes
$("[title='" + columnName + " possible values'] option").each(function () {
var thisText = $(this).text();
var thisVal = $(this).val()
var thisSnippet = "” + thisText + “”;
ckBox.push(thisSnippet);
});
// loop through all the selected options and draw the checkboxes
$(“[title='” + columnName + ” selected values’] option”).each(function () {
var thisText = $(this).text();
var thisVal = $(this).val()
var thisSnippet = “” + thisText + “”;
ckBox.push(thisSnippet);
});
ckBox.sort();
for (index=0; index < ckBox.length; ++index) {
thisDiv.append(ckBox[index]);
}
To be clear, when I said it sorts the choices by value, I meant the html value attribute, which is the contents of thisText. If you want to sort by thisVal, you can simply reverse the order of the value and id attributes in the snippet.
Nice – thanks for that. We actually decided against this approach for a couple of other reasons and wound up purchasing a product that did the same thing server-side. But, having the sort stay consistent is definitely a big deal and one that I knew would need to be fixed at some point.
Also, I’m not using the GetListItems SPServices call for filtering. I’m using a bit of a kludge by having a hidden field with a copy of the main field, if the conditions are right. i.e. Calculated field: IF([itemisactive],[lookupfield],””).
When I try to use this code, I get an errors;
First was that length was not defined in the
Then was giving me an undefined for the alert.
Now Object Expected at “checkByValue(value);”.
I know I’ve entered all the correct variables; I’m having different errors every time I try a new method: place code above vs below, and even tried code alterations suggested.
I was able to use the basic draw checkboxes perfectly, just no edit.
Any help is appreciated: Win7, IE8, SP2010
The complete file download links have dropped off….
Any thoughts of adding a select all checkbox….(pesky users)?
It wouldn’t be hard to do. You just need to add an extra checkbox above your thisDiv div of checkboxes and then use jQuery to check the boxes in the div. Here’s a reference:
http://www.sanwebe.com/2014/01/how-to-select-all-deselect-checkboxes-jquery
I looked into it. It checks the boxes, but that is it. It actually doesn’t add the items. That is of course assuming I did it right.
I’m guessing that you haven’t done it quite right, then, or something has changed since I did this. I never ended up using it in production. (We bought SparQube Lookup Column instead.) But, it was working to add the items.
Hi, this is great !
Now what I try to accomplish is the other way round. Due to the Lookup Fields limitation of 8 Lookup Columns in a List in SP2010 I need to change some lookup columns into Choice columns with multiple selections.
With the “Checkboxes (allow multiple Selections)” selected, I get a really long checkbox list = Bad looking as there are more than 20 choices.
I’d like to have a choice column and having a Lookup Look and Feel (Two boxes) in the ListForms to keep the Forms small and neat.
Is there also a way to do this?
I haven’t attempted that. We have used CSS to make a long list of checkboxes appear less unwieldy. I’ve never thought the SharePoint 2 box implementation was very elegant.
Has anyone gotten this to work in 2013? I get the checkboxes to work, but its not actually saving the checked values. Maybe because you need to use “;#;#” as the delimiter between the IDs of the pieces of content that should be in the lookup column? Where is the delimiter being set in this example?
Hi Zach, have you managed to save it in 2013?
No:( we gave up and moved on
It is not saving the checkboxes in SharePoint 2013. It was working with 2010 nicely.
have you tried using it in office 365 and csr display templates
yes i even tried it in office 365 it is not saving the values in my sharepoint list. i was able to get the checkboxes checked when an item is edit but not saving the values