18.01.2011 I have posted a new solution compatible with both SP2007 and SP2010 and fixes the problems with rich text fields and “single lookup with more than 20 items under Internet Explorer – problem”. You find it her
23.01.2010 Updated the code to fix two issues regarding date and time columns. I added a <style> tag to set the font size of “.ms-dtinput” and “.ms-dttimeinput” to 0.7em.
I also added a custom handler to select the right tab on “empty field validation” on a date and time field. These are validated without page reload, and therefore did not work in the previous version.
Thank you all for the feedback and the testing.
15.12.2009 Update to support form validation. On submit – if there are required fields not filled – the tab containing the first required field is selected.
I got this request:
We have a custom list with a lot of fields. I need to divide it into sections and then easily show/hide those sections. I am going to try dividing the form into div tags and then use jQuery to display the sections in either Tabs or an accordion…
And made this demo based on the jQuery UI Widget “Tabs”.
NewForm:

DispForm:

DispForm with attachment:

As always we start like this:
Create a document library to hold your scripts (or a folder on the root created in SharePoint Designer). In this example i have made a document library with a relative URL of “/test/English/Javascript” (a sub site named “test” with a sub site named “English” with a document library named “Javascript”):

A folder named “jQueryUI” containing the scripts and the “images”-folder for the selected theme:

The jQuery-library is found here. The pictures and the sourcecode refers to jquery-1.3.2.min. If you download another version, be sure to update the script reference in the sourcecode.
The jQuery UI-library is found here. Find the theme of your choice – mine is “smootness” – and download the files (i have plucked only the necessary files – “UI Core” and “Tabs”).
Add a CEWP below your NewForm, DispForm and EditForm.
Add this code:
<!-- Date field text size -->
<style type="text/css">
.ms-dtinput,.ms-dttimeinput{
font-size:0.7em;
}
</style>
<DIV id="tabs">
<UL style="font-size:12px">
<LI><A href="#tabs-1">Tab 1</A></LI>
<LI><A href="#tabs-2">Tab 2</A></LI>
<LI><A href="#tabs-3">Tab 3</A></LI>
<LI><A href="#tabs-4">Attachments</A></LI>
</UL>
<div><table cellpadding="0" cellspacing="0" id="tabs-1"></table></div>
<div><table cellpadding="0" cellspacing="0" id="tabs-2"></table></div>
<div><table cellpadding="0" cellspacing="0" id="tabs-3"></table></div>
<div><table cellpadding="0" cellspacing="0" id="tabs-4"></table></div>
</DIV>
<link type="text/css" href="/test/English/Javascript/jQueryUI/jquery-ui-1.7.2.custom.css" rel="stylesheet" />
<script type="text/javascript" src="/test/English/Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/jQueryUI/jquery-ui-1.7.2.custom.min.js"></script>
<script type="text/javascript">
// Array of all fields - format: tabID|FieldInternalName
arrTab = ['1|Title','1|Tab1Text','1|Tab1Choice',
'2|Responsible','2|Tab2Text','2|Tab2Choice','2|Date',
'3|Tab3Text','3|Tab3Choice','3|Tab3MultilinePlain'];
// Initiate all the fields
fields = init_fields();
// Add the "tabs" to the formtable
$("#tabs").insertAfter('.ms-formtable').tabs();
// Loop trough all fields and move them to the right tab
$.each(arrTab,function(idx,item){
var split = item.split('|');
var tabID = split[0];
var fieldName = split[1];
if(fields[fieldName]!=undefined){
currField = $(fields[fieldName]);
currField.appendTo('#tabs-'+tabID);
}
});
// Are there any required fields not filled? - select the tab containing the first field
selectTabOnFormValidation(false);
function selectTabOnFormValidation(preSave){
var formvalidationTab = '';
// Formvalidation - find the first tab with empty required fields
$.each(arrTab,function(idx,item){
var split = item.split('|');
var tabID = split[0];
var fieldName = split[1];
currField = $(fields[fieldName]);
// Handles DateTimeField (empty field validation is performed without page reload)
if(currField.find("SPAN[ID*='_DateTimeField_']").length>0){
if(currField.find('input:first').val()=='' && preSave){
formvalidationTab = tabID;
}
}
if(formvalidationTab == '' && currField.find('.ms-formbody span.ms-formvalidation').length>0){
formvalidationTab = tabID;
}
});
// Select the first tab containing an empty required field
if(formvalidationTab!=''){
$('#tabs').tabs('select', formvalidationTab);
}
}
// Move the Attachment's to the last tab
$("#idAttachmentsRow").appendTo('#tabs-4').find('.ms-formlabel').attr('width','165px');
// function - to make "object" of all tr's in the form
function init_fields(){
var res = {};
$("td.ms-formbody").each(function(){
if($(this).html().indexOf('FieldInternalName="')<0) return;
var start = $(this).html().indexOf('FieldInternalName="')+19;
var stopp = $(this).html().indexOf('FieldType="')-7;
var nm = $(this).html().substring(start,stopp);
res[nm] = this.parentNode;
});
return res;
}
// Catch "empty field validation" on date and time columns
function PreSaveAction(){
selectTabOnFormValidation(true);
return true;
}
</script>
The only parameters you need to edit in the script is the array of FieldInternalNames. The format of the variable “arrTab” is tabID|FieldInternalName.
In the html above the script, adapt the number’s of tabs – and the tab’s display name. The tabID corresponds with the number in the id attribute of the table to insert the tab content in.
All fields must be added to a tab – if not it looks ugly….
Note: By now i have tested and found that columns of type “Multiple lines of text (Rich text or Enhanced rich text) do not work. What happens is that the tabs script shows some of the fields hidden parts.
I have not done any testing on how to prevent this issue, so feel free to notify me if you find a workaround.
Regards
Alexander
December 2, 2010 at 11:52 pm |
Hello Alexander,
We solved the Safari issue by replacing the following code snippet. If you have a better solution please advise.
function init_fields(){
var res = {};
var b = “hello world”;
$(“td.ms-formbody”).each(function(){
var Original = $(this).html();
if(Original.indexOf(‘FieldInternalName=”‘)<0) return;
var nm = Original.substr(Original.indexOf('FieldInternalName='));
nm = nm.substr(nm.indexOf('"')+1);
nm = nm.substring(0,nm.indexOf('"'));
res[nm] = this.parentNode;
});
return res;
}
Kind regards,
Mario
December 3, 2010 at 12:00 am
Hi,
I’m a bit behind on handling all the questions i receive… Look here for another possible solution
Alexander
December 6, 2010 at 3:09 pm |
Hi,
anyone find a Solution for the multiple line field showing the hidden parts??
December 6, 2010 at 3:20 pm |
Hi,
New problem …
For example we have two lookup fields on unmodified form, first lookup on tab1, another on tab2. If we click for dropdown on lookup at any tab all will be fine, but on another tab it wont show up anymore. No errors in browser.
December 6, 2010 at 6:12 pm
Checked with clear list – same thing.
Checked with another (custom)loookup field – same error.
Seems like something wrong whith ShowDropdown func when it called by controls from different tables …
December 7, 2010 at 10:03 am
Btw, all lookups whith more than 20 items.
December 9, 2010 at 5:08 pm
Im the only one who got this problem?
December 22, 2010 at 12:09 pm
Hello?!
December 22, 2010 at 12:49 pm
Hi,
There are some issues wit single lookup columns with more than 20 item (in IE only) and with rich text fields. I have no generic way to fix these issues, sorry
Alexander
December 22, 2010 at 12:51 pm
By the way, it you do not include them in any tab – they will appear “outside” the tabs, but should work.
Alexander
December 23, 2010 at 10:35 am
Mabye this give You some idea of whats going on :
I’ve placed to buttons, first calls ShowDropdown for lookup in tab1, second in tab2.
So what i got : First button show dropdown as it should, second shows dropdown on the top of the page (just the end of dropdown visible because it appears under ribbon ). So dropdowns appears, but in wrong position ( seems like they even in right tab )
Also another solution could be alternative way to build tabs – not moving them to another table, but to show/hide them depending on what tab is clicked … but im too weak in java script to perform this :’(
December 23, 2010 at 10:37 am
Does anyone know where showdropdown function located ( what script name )?
December 23, 2010 at 12:23 pm
Ok, we got 3 functions :
1. ShowDropdown ( error appears at last line when target control must be focused )
2. EnsureSelectElement
3. FilterChoice
FilterChoice sets position and z-order of our listbox, so here we can change it to our needs.
But i cant understand how to override FilterChoice so control use our modified version of this function. Any suggestions?
Idea is to place overrided version in CWEP in forms where tabs used to save original version.
December 7, 2010 at 4:12 pm |
One more question :
My page contains custom fields which refreshes page in some cases.
When page refresh active tab becomes first one. Is there any solution for this?
Thx))
December 7, 2010 at 5:20 pm
Ok… so … we can restore tab ID from cookie by adding something like this :
$tabs.tabs(‘select’, Number($.cookie(“tabNumber”)));
But how to ‘catch’ when tab clicked to save its id in cookies?
December 10, 2010 at 11:29 am
Full explanation how to use cookies to restore tab position after page refresh : http://stackoverflow.com/questions/2325342
December 23, 2010 at 4:27 pm |
Ooookkk… Thats was not easy but…
We got core function FilterChoice and the only way i found to override it is to modify master page ( v4 for SP2k10 ).
Its not the way i want it to be, but for now its the only way i found ( any ideas how to fully load core.js without modifying master page are more than welcome!! )
So, modifying master page :
1. Looking for SharePoint:ScriptLink language=”javascript” name=”core.js”
2. Modifying to OnDemand=”False” Defer=”False”
Now we easily can override our FilterChoice to our own in CWEP.
Ill try to “correct” original FilterChoice and post here, but still hope someone help me, because all this sharepoint stuff totally blowing up my brains and im not js programmer at all
December 23, 2010 at 4:36 pm
Simply calling FilterChoice before overriding is not working – dont know why.
December 23, 2010 at 4:52 pm
For now i really need some help
Visually it looks like listbox shows only on tab on which it was called for a first time, but i cant get where this happening …
function FilterChoice(opt, ctrl, strVal, filterVal) {ULSsa6:; var i; var cOpt=0; var bSelected=false; var strHtml=""; var strId=opt.id; var strName=opt.name; var strMatch=""; var strMatchVal=""; var strOpts=ctrl.choices; var rgopt=strOpts.split("|"); var x=AbsLeft(ctrl); var y=AbsTop(ctrl)+ctrl.offsetHeight; var elmWorkspace=document.getElementById("s4-workspace"); if(elmWorkspace) y -=AbsTop(elmWorkspace); var strHidden=ctrl.optHid; var iMac=rgopt.length - 1; var iMatch=-1; var unlimitedLength=false; var strSelectedLower=""; if (opt !=null && opt.selectedIndex >=0) { bSelected=true; strSelectedLower=opt.options[opt.selectedIndex].innerText; } for (i=0; i < rgopt.length; i=i+2) { var strOpt=rgopt[i]; while (i < iMac - 1 && rgopt[i+1].length==0) { strOpt=strOpt+"|"; i++; if (i < iMac - 1) { strOpt=strOpt+rgopt[i+1]; } i++; } var strValue=rgopt[i+1]; var strLowerOpt=strOpt.toLocaleLowerCase(); var strLowerVal=strVal.toLocaleLowerCase(); if (filterVal.length !=0) bSelected=true; if (strLowerOpt.indexOf(strLowerVal)==0) { var strLowerFilterVal=filterVal.toLocaleLowerCase(); if ((strLowerFilterVal.length !=0) && (strLowerOpt.indexOf(strLowerFilterVal)==0) && (strMatch.length==0)) bSelected=false; if (strLowerOpt.length > 20) { unlimitedLength=true; } if (!bSelected || strLowerOpt==strSelectedLower) { strHtml+="<option selected value=\""+strValue+"\">"+STSHtmlEncode(strOpt)+"</option>"; bSelected=true; strMatch=strOpt; strMatchVal=strValue; iMatch=i; } else { strHtml+="<option value=\""+strValue+"\">"+STSHtmlEncode(strOpt)+"</option>"; } cOpt++; } } var strHandler=" ondblclick=\"HandleOptDblClick()\" onkeydown=\"HandleOptKeyDown()\""; var strOptHtml=""; if (unlimitedLength) { strOptHtml="<select tabIndex=\"-1\" ctrl=\""+ctrl.id+"\" name=\""+strName+"\" id=\""+strId+"\""+strHandler; } else { strOptHtml="<select class=\"ms-lookuptypeindropdown\" tabIndex=\"-1\" ctrl=\""+ctrl.id+"\" name=\""+strName+"\" id=\""+strId+"\""+strHandler; } if (cOpt==0) { strOptHtml+=" style=\"display:none;position:absolute;z-index:2;left:"+x+ "px;top:"+y+ "px\" onfocusout=\"OptLoseFocus(this)\"></select>"; } else { strOptHtml+=" style=\"position:absolute;z-index:2;left:"+x+ "px;top:"+y+ "px\""+ " size=\""+(cOpt <=8 ? cOpt : 8)+"\""+ (cOpt==1 ? "multiple=\"true\"" : "")+ " onfocusout=\"OptLoseFocus(this)\">"+ strHtml+ "</select>"; } opt.outerHTML=strOptHtml; var hid=document.getElementById(strHidden); if (iMatch !=0 || rgopt[1] !="0" ) hid.value=strMatchVal; else hid.value="0"; if (iMatch !=0 || rgopt[1] !="0" ) return strMatch; else return ""; }December 23, 2010 at 5:06 pm
Just btw, wrong listbox position can be fixed same way too
December 23, 2010 at 5:41 pm
Another func that can help :
function EnsureSelectElement(ctrl, strId)
{ULSsa6:;
var select=document.getElementById(strId);
if (select==null)
{
select=document.createElement(“SELECT”);
ctrl.parentNode.appendChild(select);
select.outerHTML=”";
FilterChoice(select, ctrl, ctrl.value, “”);
}
return document.getElementById(strId);;
}
December 24, 2010 at 2:00 pm
Well, some progress :
I’ve override two functions ( only one need to solve problem with
“disappearing” lookup element )
First :
EnsureSelectElement
add $(select).appendTo(ctrl.parentNode); right before return select;
This works, but still got problem : first called dropdown in tab table will not hide on click event. Any ideas? And one more thing, i’ve removed name tag in outerHTML of select object, i have no idea why, but if it is used then in browser it will get “WPQ4″ variable, which i dont know where and what is it …
Second :
FilterChice
add – 30 to y variable.
Well, this fixes vertical position problem. But i use constant value so the question is how to get tabs area height dynamically?
January 8, 2011 at 11:44 am
Hi,
I finally got to look at this one. I have located the “fix” and will post another “version” of this article within a week. This article will address the “lookup with more than 20 items” and Rich text fields problems.
For now you can fix the lookup problem by adding one line to the function “EnsureSelectElement” and include it in your existing code (do NOT edit it in core.js):
function EnsureSelectElement(ctrl, strId){ $("#"+strId).remove(); var select=document.getElementById(strId); if (select==null) { select=document.createElement("SELECT"); ctrl.parentNode.appendChild(select); select.outerHTML="<select id=\""+strId+"\" ctrl=\""+ctrl.id+"\" class=\"ms-lookuptypeindropdown\" name=\""+strId+"\" style=\"display:none\" onfocusout=\"OptLoseFocus(this)\"></select>"; FilterChoice(select, ctrl, ctrl.value, ""); } return document.getElementById(strId);; }Line 02 is added to force the recreateion of the “_Select” each time it is used.
Stay tuned for the updated version which no longer needs to load jQueryUI-library.
Alexander
January 11, 2011 at 8:10 pm |
I simply chose to override FilterChoice like ian suggested and this worked:
function FilterChoice(opt, ctrl, strVal, filterVal) {
...
var offSet = $(ctrl).position();
var x = offSet.left;
var y = offSet.top+15;
...
}
This will fix the list box with more than 20 items moving. I haven’t looked into the other issues as this hasn’t affected me.
January 14, 2011 at 11:44 am
Greate! Works on SP 2010
If someone got problem in EnsureControls – just remove name tag.
Still little problem : some fields not getting focus, so dropdown not hiding on lose focus .. will try to see whats the problem is ..
January 11, 2011 at 8:12 pm |
Sorry about the name duplication! I shall call myself…#2
January 16, 2011 at 7:15 pm |
Hi all,
I have made a new and improved solution for tabbed SharePoint forms. It will be posted over at https://www.nothingbutsharepoint.com within a few days.
Keep your eyes open for it!
Alexander
January 18, 2011 at 8:01 pm |
You find the new solution here
Alexander
March 3, 2011 at 6:27 pm |
Hi Alexander. Is there any way to combine this solution with your Fields Side by Side solution? I tried to put both scripts on my DispForm and it “worked” but with undesireable results.
For example: the side by side fields picked up strange styles, and they appear on every tab instead of just after the single appended field that I specified in the CEWP.
For me it would be the ultimate in control over these form pages.
March 7, 2011 at 10:16 pm
Hi,
The “side by side” is the most “destructive” of my scripts and is not easy to fit in with other scripts. I would not recommend it. If you want to do it you must look into the init_field function – calling it multiple times to adapt to the “morphing form”.
Have you looked at the latest tabs solution?
Alexander
March 8, 2011 at 5:21 pm
Hi,
I’ve successfully implemented the TabsInForm and SideBySide Scripts on a number of pages and so far have only discovered two minor problems, first when you have a mandatory field you have to click “OK” twice to save the form, secondly, when you have a large lookup field the dropdown will open outside the side by side frame.
You can even combine these scripts with the “BuildHeadingsFromArray” but that is not very reliable and sometimes fails for reasons I have not yet understood.
The trick to get this working is:
- TabsInForm comes first
- FieldsSideBySide is second
- Create “dummy” fields depending on the number of your tabs
Assign the fields to your tabs in “TabsInForm” and then attach the fields with “FieldsSideBySide” to the dummy fields, making them the topmost fields per tab.
A single field, e.g. standard input field, will define the width of the box, short fields will not always expand to the full width, that’s were you might experience messed up styles.
If you feel the style is too messed up insert a standard field to force the other ones to expand, I haven’t tried it but I think even a hidden field will do the trick.
If you have more questions feel free to ask.
Chris
March 18, 2011 at 12:08 am
Thanks Chris, I need to try that out soon. By “dummy field” do you mean create an actual column?
Do you ever have fields that you’ve specified on one tab repeat on multiple tabs?
March 22, 2011 at 11:53 am
Yes, “dummy fields” refer to actual columns that I hide with a small “hide field” script. Regarding the fields, no, I only use them once and have never found them to repeat on other tabs.
Chris
March 18, 2011 at 12:17 am |
Alexander, in the new solution, can you turn off the Attachments field somehow? I’ve tried commenting out the lines, deleting the lines, renaming the tab, etc. but I can’t successfully remove it. Thanks!
May 24, 2011 at 9:19 pm |
In our SharePoint projects we use a tool to customize SharePoint forms: Advanced Forms for SharePoint (http://www.kaldeera.com)
Hope this helps.
January 20, 2012 at 9:20 am |
HI guys,
I am not sure if i am posting here would help me or need to post somewhere else..
i need a help i am new to sharepoint and have taken a initiative to build a form for handling a project requests
a kind of tab form similar to an example above,
1st Tab has RDD form
2nd Tab with TDD form
3rd Tab with Testing Form
4th Tab with Project feedback form
and once they enter all the detials it should be stored in a repository where i could go look out for…
Needed you help guys……
thanks in advance
January 27, 2012 at 10:09 pm
Hi,
Take a look at his one
Alexander