This is the updated version of the Project Gantt Chart view for SharePoint Online.
Over 2 years ago I published a Gantt Chart view for Tasks in SharePoint Online both here and on github. After publishing I have received numerous questions and suggestions and even an alternative version was created by Federico Sapia.
An updated version
The ideas from Federico’s version and suggestions made by several people got me triggered to create an updated version. But, yeah, time flies.
Apparently summer holidays are good for something because I finally made some time to get back to the initial version.
First of all, it is cleaner. The bar is no longer changing colours depending on the state of the task. It is just blue or lightblue, using the same shades of blue as Project for the web. And for the rest, this new version now supports/includes:
- Milestones
- Progressbar
- Clicks to update the progress
- Task description
- Task assignment
- Labels that mover from right to left based on the amount of space.

To accomedate these changes I needed three more columns.
Columnname | Columntype | |
---|---|---|
Title | Text | |
ProjectStart | Date and time | |
ProjectDue | Date and time | |
TaskStart | Date and time | |
TaskDue | Date and time | |
Progress | Number (min: 0, max:100, percentage) | |
TaskType | Choice (2 options: Task, Milestone) | New |
AssignedToUser | People (Single select) | New |
TaskDescription | Multilines of text (no format) | New |
Please note that whenever you create a column an internal name is assigned to this column. If you change the name of a column, you do not change the internal name. So make sure you use the correct name straight away.
The code
If you don’t know how to create a view and apply the code below, please do check the post of the orginal SharePoint Project Gantt Chart, just make sure that all of the above columns are used in your view.
{ "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/row-formatting.schema.json", "hideSelection": true, "hideColumnHeader": true, "rowFormatter": { "elmType": "div", "style": { "height": "=if(@rowIndex == 0, '88px', '52px')", "display": "block", "width": "100%", "position": "sticky" }, "attributes": { "class": "ms-bgColor-neutralLighter--hover" }, "children": [ { "elmType": "div", "_comment": "Header area", "attributes": { "class": "ms-bgColor-themePrimary" }, "style": { "width": "100%", "display": "=if(@rowIndex == 0, 'flex', 'none')", "height": "36px", "padding": "0", "font-weight": "bold", "border-radius": "6px 6px 0 0" }, "children": [ { "elmType": "div", "txtContent": "Task", "style": { "width": "220px", "text-align": "left", "padding-left": "0.4em", "box-sizing": "border-box" }, "attributes": { "class": "ms-fontSize-16 ms-fontColor-white" } }, { "elmType": "div", "style": { "flex-grow": "1", "height": "100%", "position": "relative" }, "children": [ { "elmType": "div", "_comment": "ProjectStart label", "txtContent": "=toLocaleDateString([$ProjectStart])", "style": { "position": "absolute", "padding": "14px 4px 0 4px", "height": "22px", "border-radius": "6px 6px 0 0" }, "attributes": { "title": "='Project Start: ' + toLocaleDateString([$ProjectStart])", "class": "ms-bgColor-themeDarker ms-fontSize-14 ms-fontColor-white" } }, { "elmType": "div", "_comment": "ProjectDue label", "txtContent": "=toLocaleDateString([$ProjectDue])", "style": { "position": "absolute", "right": "0", "padding": "14px 4px 0 4px", "height": "22px", "border-radius": "6px 6px 0 0" }, "attributes": { "title": "='Project Finish: ' + toLocaleDateString([$ProjectDue])", "class": "ms-bgColor-themeDarker ms-fontSize-14 ms-fontColor-white" } }, { "elmType": "span", "_comment": "CurrentDate label", "txtContent": "=toLocaleDateString( @now)", "style": { "position": "relative", "width": "90px", "z-index": "100", "display": "=if([$ProjectDue] < @now , 'none', 'block')", "left": "=floor( (Number(@now)-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])) * 100 ) + '%'", "background-color": "#e1dfdd", "text-align": "center", "padding": "0 3px", "margin": "0 0 0 3px" } }, { "elmType": "span", "_comment": "Vertical line for today", "attributes": { "class": "ms-fontColor-gray40" }, "style": { "position": "relative", "display": "=if( [$ProjectDue] < @now , 'none', 'block')", "top": "-1.3em", "z-index": "1", "border-left": "5px solid", "height": "800px", "width": "0.1em", "left": "= (Number(@now)-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])) * 100 + '%' " } } ] } ] }, { "elmType": "div", "_comment": "Rows", "style": { "width": "100%", "display": "flex" }, "children": [ { "elmType": "div", "_comment": "Row (task) header", "style": { "width": "220px", "display": "flex", "flex-wrap": "wrap" }, "attributes": { "class": "" }, "children": [ { "elmType": "span", "_comment": "Progress circle icon ", "style": { "width": "24px", "padding": "6px 0", "text-align": "center", "cursor": "pointer" }, "attributes": { "iconName": "=if([$Progress] >= 1, 'CompletedSolid', if([$Progress] > 0 , 'CortanaLogoReadyOuter', 'CircleRing'))", "title": "='Progress: ' + Number([$Progress] * 100) + '%'", "class": "= 'ms-fontSize-14 ms-fontColor-' + if([$Progress] >= 1, 'green', 'neutralSecondaryAlt')" }, "customRowAction": { "action": "setValue", "actionInput": { "Progress": "=if([$Progress] == 0, if([$TaskType] == 'Task' || [$TaskType] == '', 25 , 100) , if([$Progress] == 0.25 , 50, if([$Progress] == 0.50, 75, if([$Progress] == 0.75, 100, 0))))" } } }, { "elmType": "button", "_comment": "tasktitle", "txtContent": "[$Title]", "customRowAction": { "action": "editProps" }, "style": { "width": "196px", "height": "1.6em", "padding": "0.3em 0 0 0", "border": "none", "background-color": "transparent", "cursor": "pointer", "text-decoration": "none", "text-align": "left", "outline": "none", "display": "inline-block", "overflow": "hidden", "text-overflow": "ellipsis", "white-space": "nowrap" }, "attributes": { "title": "[$Title]", "class": "ms-fontSize-14 ms-fontWeight-semibold ms-fontColor-gray140 ms-fontColor-black--hover" } }, { "elmType": "span", "_comment": "Task status warning", "style": { "width": "24px", "padding": "1px 0 0 0", "text-align": "center" }, "attributes": { "iconName": "=if( ( ([$TaskType] == 'Task' || [$TaskType] == '') && [$TaskDue]< @now && [$Progress] < 1 ) || ([$TaskType] == 'Milestone' && [$TaskStart]< @now && [$Progress] < 1 ) , 'EventDateMissed12', '')", "title": "This task is running late!", "class": "='ms-fontSize-14 ms-fontColor-' + if([$TaskDue]< @now && [$Progress] < 1, 'sharedRed20', 'themePrimary')" } }, { "elmType": "div", "txtContent": "=toLocaleDateString([$TaskStart])", "style": { "width": "96px", "padding": "0.1em 0", "text-align": " center", "heigth": "1.4em", "border-radius": "12px", "margin": "0 2px 0 0 " }, "attributes": { "class": "ms-fontSize-12 ms-bgColor-neutralLight" } }, { "elmType": "div", "txtContent": "=toLocaleDateString([$TaskDue])", "style": { "width": "96px", "padding": "0.1em 0", "text-align": " center", "border-radius": "12px", "margin": "0 2px 0 0 " }, "attributes": { "class": "ms-fontSize-12 ms-bgColor-neutralLight" } } ] }, { "elmType": "div", "_comment": "Ganttchart area", "style": { "flex-grow": "1", "position": "relative", "height": "3.3em", "padding": "0.3em 0 0 0" }, "attributes": { "class": "" }, "children": [ { "elmType": "div", "_comment": "NormalTask Bar", "txtContent": "", "style": { "position": "absolute", "box-sizing": "border-box", "display": "=if([$TaskType] == 'Task' || [$TaskType] == '' , 'flex', 'none')", "border-radius": "6px", "z-index": "10", "top": "0.6em", "height": "2.4em", "overflow": "hidden", "text-overflow": "ellipsis", "border": "1px solid", "border-color": "#0078db", "background-color": "#cfe6f7", "left": "= (Number([$TaskStart])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])) * 100 + '%'", "width": "= if( [$TaskDue] > [$ProjectDue], (Number([$ProjectDue])-Number([$TaskStart])+ 86400000) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 , (Number([$TaskDue])-Number([$TaskStart])+ 86400000) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 ) + '%'" }, "attributes": { "class": "", "title": "" } }, { "elmType": "div", "_comment": "NormalTask Progress Bar", "style": { "position": "absolute", "box-sizing": "border-box", "display": "=if(( [$TaskType] == 'Task' || [$TaskType] == '' ) && [$Progress] > 0, 'flex', 'none')", "border-radius": "=if( [$Progress] < 1, '6px 0 0 6px', '6px')", "z-index": "20", "top": "0.6em", "height": "2.4em", "overflow": "hidden", "text-overflow": "ellipsis", "border": "1px solid", "border-color": "#0078db", "background-color": "#0078db", "left": "= (Number([$TaskStart])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])) * 100 + '%'", "width": "= if( [$TaskDue] > [$ProjectDue], ((Number([$ProjectDue])-Number([$TaskStart])+ 86400000) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100) * [$Progress] + '%' , ((Number([$TaskDue])-Number([$TaskStart])+ 86400000) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 * [$Progress]) + '%'" }, "attributes": { "class": "sp-field-bold", "title": "=[$Title] + ' - ' + toLocaleDateString([$TaskStart]) + ' - ' + toLocaleDateString([$TaskDue])" } }, { "elmType": "div", "_comment": "Bar Placeholder for customcard", "txtContent": "", "style": { "position": "absolute", "box-sizing": "border-box", "border-radius": "6px", "z-index": "50", "top": "0.6em", "height": "2.4em", "overflow": "hidden", "text-overflow": "ellipsis", "border": "=if([$TaskDue]< @now && [$Progress] < 1 && ([$TaskType] == 'Task' || [$TaskType] == '' ), '2px solid #f8b7bd', 'none')", "background-color": "", "left": "= (Number([$TaskStart])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])) * 100 + '%'", "width": "=if([$TaskType] == 'Milestone', '28px' , if( [$TaskDue] > [$ProjectDue], (Number([$ProjectDue])-Number([$TaskStart])+ 86400000) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 , (Number([$TaskDue])-Number([$TaskStart])+ 86400000) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 ) + '%'", "margin-left": "=if([$TaskType] == 'Milestone', '-14px' , 0" }, "attributes": { "class": "", "title": "" }, "customCardProps": { "openOnEvent": "hover", "directionalHint": "bottomCenter", "isBeakVisible": true, "beakStyle": { "backgroundColor": "white" }, "formatter": { "elmType": "div", "style": { "max-height": "256px", "width": "282px", "display": "flex", "flex-wrap": "wrap", "align-items": "flex-start" }, "attributes": { "class": "ms-ContextualMenu-list is-open list-436" }, "children": [ { "elmType": "div", "txtContent": "[$Title]", "style": { "width": "250px", "height": "40px", "padding": "4px 4px 0 4px", "overflow": "hidden", "text-overflow": "ellipsis" }, "attributes": { "class": "ms-fontSize-14 ms-bgColor-themeLight ms-fontWeight-semibold ms-fontColor-gray160" } }, { "elmType": "div", "style": { "width": "12", "flex-grow": "1", "height": "34px", "padding": "10px 0 0 0 ", "text-align": "center", "cursor": "pointer" }, "attributes": { "iconName": "Edit", "class": "ms-fontSize-14 ms-bgColor-themeLight ms-fontColor-gray160" }, "customRowAction": { "action": "editProps" } }, { "elmType": "div", "_comment": "Progress actionbar", "style": { "width": "100%", "display": "flex", "flex-wrap": "wrap", "align-items": "flex-start", "margin": "2px 0" }, "children": [ { "elmType": "div", "style": { "width": "24px", "padding": "6px 0", "text-align": " center", "heigth": "1.4em" }, "attributes": { "iconName": "Timeline" } }, { "elmType": "div", "txtContent": "0%", "style": { "padding": "2px 6px", "text-align": " center", "border-radius": "14px", "margin": "2px 2px 0 0 ", "cursor": "pointer", "heigth": "1.4em" }, "attributes": { "class": "='ms-fontSize-14 ms-bgColor-themeLight--hover ms-fontColor-themeDarker--hover ms-bgColor-' + if([$Progress] == 0, 'themeTertiary', 'neutralLight')" }, "customRowAction": { "action": "setValue", "actionInput": { "Progress": "0" } } }, { "elmType": "div", "txtContent": "25%", "style": { "padding": "2px 6px", "text-align": " center", "border-radius": "14px", "margin": "2px 2px 0 0 ", "cursor": "pointer", "heigth": "1.4em" }, "attributes": { "class": "='ms-fontSize-14 ms-bgColor-themeLight--hover ms-fontColor-themeDarker--hover ms-bgColor-' + if([$Progress] == 0.25, 'themeTertiary', 'neutralLight')" }, "customRowAction": { "action": "setValue", "actionInput": { "Progress": "25" } } }, { "elmType": "div", "txtContent": "50%", "style": { "padding": "2px 6px", "text-align": " center", "border-radius": "14px", "margin": "2px 2px 0 0 ", "cursor": "pointer", "heigth": "1.4em" }, "attributes": { "class": "='ms-fontSize-14 ms-bgColor-themeLight--hover ms-fontColor-themeDarker--hover ms-bgColor-' + if([$Progress] == 0.5, 'themeTertiary', 'neutralLight')" }, "customRowAction": { "action": "setValue", "actionInput": { "Progress": "50" } } }, { "elmType": "div", "txtContent": "75%", "style": { "padding": "2px 6px", "text-align": " center", "border-radius": "14px", "margin": "2px 2px 0 0 ", "cursor": "pointer", "heigth": "1.4em" }, "attributes": { "class": "='ms-fontSize-14 ms-bgColor-themeLight--hover ms-fontColor-themeDarker--hover ms-bgColor-' + if([$Progress] == 0.75, 'themeTertiary', 'neutralLight')" }, "customRowAction": { "action": "setValue", "actionInput": { "Progress": "75" } } }, { "elmType": "div", "txtContent": "100%", "style": { "padding": "2px 6px", "text-align": " center", "border-radius": "14px", "margin": "2px 2px 0 0 ", "cursor": "pointer", "heigth": "1.4em" }, "attributes": { "class": "='ms-fontSize-14 ms-bgColor-themeLight--hover ms-fontColor-themeDarker--hover ms-bgColor-' + if([$Progress] == 1, 'themeTertiary', 'neutralLight')" }, "customRowAction": { "action": "setValue", "actionInput": { "Progress": "100" } } } ] }, { "elmType": "div", "_comment": "Warning ICON for Late tasks", "style": { "width": "24px", "display": "=if( ( ([$TaskType] == 'Task' || [$TaskType] == '') && [$TaskDue]< @now && [$Progress] < 1 ) || ([$TaskType] == 'Milestone' && [$TaskStart]< @now && [$Progress] < 1 ) , 'block', 'none')", "padding": "6px 0 7px 0", "text-align": " center", "heigth": "1.4em", "margin": "2px 0" }, "attributes": { "iconName": "EventDateMissed12", "class": "sp-field-severity--blocked30 ms-fontSize-14 ms-fontColor-sharedRed20" } }, { "elmType": "div", "_comment": "Warning TEXT for Late tasks", "txtContent": "This task is running late!", "style": { "width": "254px", "display": "=if( ( ([$TaskType] == 'Task' || [$TaskType] == '') && [$TaskDue]< @now && [$Progress] < 1 ) || ([$TaskType] == 'Milestone' && [$TaskStart]< @now && [$Progress] < 1 ) , 'block', 'none')", "padding": "4px 0 4px 4px", "text-align": " Left", "heigth": "1.4em", "margin": "2px 0" }, "attributes": { "class": "sp-field-severity--blocked30 ms-fontSize-14 ms-fontColor-sharedRed20" } }, { "elmType": "div", "style": { "width": "24px", "padding": "6px 0", "text-align": " center", "heigth": "1.4em" }, "attributes": { "iconName": "Calendar" } }, { "elmType": "div", "_comment": "Task StartdDate in customCard", "txtContent": "=toLocaleDateString([$TaskStart])", "style": { "width": "127px", "padding": "2px 0", "text-align": " center", "border-radius": "14px", "margin": "2px 2px 0 0 ", "height": "1.4em" }, "attributes": { "class": "ms-fontSize-14 ms-bgColor-neutralLight" } }, { "elmType": "div", "_comment": "Task DueDate in customCard", "txtContent": "=toLocaleDateString([$TaskDue])", "style": { "width": "127px", "padding": "2px 0", "text-align": " center", "border-radius": "14px", "margin": "2px 2px 0 0 ", "height": "1.4em" }, "attributes": { "class": "ms-fontSize-14 ms-bgColor-neutralLight" } }, { "elmType": "div", "style": { "width": "24px", "padding": "6px 0", "text-align": " center", "heigth": "1.4em" }, "attributes": { "iconName": "Contact", "title": "='Assigned to : ' + [$AssignedToUser.title]" } }, { "elmType": "div", "txtContent": "[$AssignedToUser.title]", "style": { "width": "254px", "padding": "4px 0 4px 4px" }, "defaultHoverField": "[$AssignedToUser]" }, { "elmType": "div", "txtContent": "[$TaskDescription]", "style": { "font-style": "italic", "width": "254px", "padding": "4px 0 4px 4px" } } ] } } }, { "elmType": "div", "_comment": "flag for milestone", "txtContent": "", "style": { "position": "relative", "box-sizing": "border-box", "display": "=if([$TaskType] == 'Milestone', 'flex', 'none')", "z-index": "10", "top": "0.3em", "height": "3em", "left": "= (Number([$TaskStart])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])) * 100 + '%'", "margin-left": "-14px", "width": "28px" }, "attributes": { "iconName": "=if([$TaskStart]< @now && [$Progress] < 1, 'EventDateMissed12', 'EventDate'", "title": "=[$Title] + ' - ' + toLocaleDateString([$TaskStart]) ", "class": "='ms-fontSize-24 ' + if([$TaskStart]< @now && [$Progress] < 1, 'ms-fontColor-sharedRed20', 'ms-fontColor-themePrimary') " } }, { "elmType": "div", "_comment": "Milestone Date label", "txtContent": "=getDate([$TaskStart]) + '-' + if(getMonth([$TaskStart])==0,'Jan',if(getMonth([$TaskStart])==1,'Feb',if(getMonth([$TaskStart])==2,'Mar',if(getMonth([$TaskStart])==3,'Apr',if(getMonth([$TaskStart])==4,'May',if(getMonth([$TaskStart])==5,'Jun',if(getMonth([$TaskStart])==6,'Jul',if(getMonth([$TaskStart])==7,'Aug',if(getMonth([$TaskStart])==8,'Sep',if(getMonth([$TaskStart])==9,'Oct',if(getMonth([$TaskStart])==10,'Nov',if(getMonth([$TaskStart])==11,'Dec',''))))))))))))", "style": { "position": "absolute", "box-sizing": "border-box", "display": "=if([$TaskType] == 'Milestone' , 'flex', 'none')", "z-index": "3", "top": "10px", "height": "24px", "margin-left": "-60px", "left": "= (Number([$TaskStart])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])) * 100 + '%'", "width": "60px", "text-align": "right" }, "attributes": { "class": "sp-field-bold ms-fontSize-14" } }, { "elmType": "div", "_comment": "Progress percentagelabel", "txtContent": "=(Number[$Progress]) * 100 + '%'", "style": { "position": "absolute", "box-sizing": "border-box", "display": "=if([$TaskType] == 'Task' || [$TaskType] == '' , 'flex', 'none')", "z-index": "3", "top": "10px", "height": "24px", "margin-left": "=if((Number([$TaskDue])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])) <= 0.9 , '10px' , '-40px')", "left": "=if((Number([$TaskDue])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])) <= 0.9 , (Number([$TaskDue])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])) * 100 + '%' , (Number([$TaskStart])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])) * 100 + '%' ) ", "width": "40px" }, "attributes": { "class": "sp-field-bold ms-fontSize-14" } } ] } ] } ] } }
[…] A new version of the Gantt Chart for SharePoint Online is available. […]
Hello! Thank you so much for this. I am working on incorporating this into our document review schedule for a yearly basis. Is there a way to segment the chart by quarters where there will be a “task” heading for each quarter? For example:
1Q2023
Document A
Document B
2Q2023
Document C
Document D
Or would it be best to just create a separate view for each quarter? Also the line specifying the current date seems to cut off halfway down the page. Thank you again!