Home › Forums › Modern DFFS › 5-Star Rating Element
Tagged: field internal name, rating, star-rating
- This topic has 1 reply, 2 voices, and was last updated 6 months, 3 weeks ago by
Alexander Bautz.
-
AuthorPosts
-
-
August 26, 2025 at 16:54 #38860
I was recently asked to replicate a form created in Microsoft Forms into a SharePoint list. This is generally straightforward, but this form had six fields which utilized the 5-star rating field. This is not an available field in SharePoint, so to replicate it I would need to create it myself. Now that I have finished building this in DFFS, I wanted to share my solution so others can use it or take some ideas that may help with other applications.
What I used:
- Number field
- HTML section
- Custom CSS
- Custom JavaScript
- Rule
Number field
I created a standard field with the following settings:- Type: Number
- Require that this column contains information: Yes
- Min: 1
- Max: 5
- Number of decimal places: 0
- Default value: Leave empty
I made this field required AND left the default empty so it would trigger an alert if a user did not make a selection. I set the min/max for a 5-star rating, but you could set this to whatever makes sense for your application–just don’t forget to modify the HTML section to accommodate your needs.
HTML section
Here is the simple HTML code I used to make the stars:
All forms (NewForm, DispForm, EditForm)<div class="star-rating"> <span class="star" data-index="1">★</span> <span class="star" data-index="2">★</span> <span class="star" data-index="3">★</span> <span class="star" data-index="4">★</span> <span class="star" data-index="5">★</span> </div>One important detail here: I placed this HTML section directly beneath the field I wanted it associated with in the DFFS form. This is very important when we get to the JavaScript as it works with the DOM tree to figure out the associated field.
Custom CSS
Note: this CSS is theme-aware. If you want to know more about making your Custom CSS theme-aware, please take a look at this other article I wrote: Theme-aware Custom CSS.The NewForm and EditForm use the primary color of the site theme while the DispForm uses neutral colors to show the stars are disabled. Here is the CSS I used to style the stars:
NewForm, EditForm/* Default styles for stars and container */ .star-rating { display: flex; width: fit-content; direction: ltr; margin-bottom: 20px; } .star { font-size: 2rem; padding: 0 5px; color: var(--ms-palette-neutralTertiaryAlt); cursor: pointer; transition: color 0.2s; } /* Overrides the stars to the right of the hovered one */ .star-rating:hover .star:hover ~ .star { color: var(--ms-palette-neutralTertiaryAlt); } /* Fills stars from the left up to the hovered one */ .star-rating:hover .star { color: var(--ms-palette-themePrimary); } /* Active (clicked) stars */ .star.active { color: var(--ms-palette-themePrimary) !important; }DispForm
/* Default styles for stars and container */ .star-rating { display: flex; width: fit-content; direction: ltr; margin-bottom: 20px; } .star { font-size: 2rem; padding: 0 5px; color: var(--ms-palette-neutralLight); } /* Active (clicked) stars */ .star.active { color: var(--ms-palette-neutralPrimaryAlt) !important; }One further note on CSS: I could not find a way to dynamically find and hide the associated number field input reliably. I ended up having to do it by targeting the field element directly by ID and hiding the last child (the label is the first child). Here is what I used:
#Field_placeholder_ID_(for_use_in_Custom_JS) > div:last-child { display: none; }You can find the appropriate ID in the “Field properties” in “Formbuilder.”
Custom JavaScript
I wanted to write the JavaScript where it would not depend on having the associated field hard-coded. In my use-case, I had 6 fields where I wanted to use this component, and I did not want to have to put the same code in 6 times or use an array of hard-coded strings just to work with all 6 associated fields. Fortunately, through inspecting the form using the developer tools I found that Alexander provides the field internal name for each field in the DFFS form through a property on the outer element of the field: data-fin. In order to get this reliably, I placed each HTML section directly beneath the field I wanted it to work with. Then I used this function to get the associated field internal name from the previous sibling element:function findFieldName(htmlElement) { const fieldInternalName = htmlElement.previousSibling.getAttribute('data-fin'); return fieldInternalName; }Now I just needed the outer element for the HTML section. To get this, I used the following function:
function findHtmlWrap(element) { let thisElement = element; let foundElement = false; let i = 0; while (foundElement === false && i < 10) { const className = thisElement.className; if (className.indexOf('htmlWrap_') > -1) { foundElement = true; } else if (className.indexOf('dffs_') > -1) { i = 10 } else { // Get the parent element to test const parentElement = thisElement.parentElement; thisElement = parentElement; } i += 1; if (i >= 10) { throw new Error("Could not find element with 'htmlWrap_' in class list."); } } return thisElement; }A few notes on this function:
- The outer wrapper for the HTML section has a class that begins with “htmlWrap_”, so this is what the code looks for.
- To prevent looking beyond the DFFS form in case something changes with the class applied on the outer wrapper of the HTML section, the code also checks for “dffs_” as a stopping point for the search.
- Finally, I set the while loop to stop at 10. If your starting point is nested farther down, be aware of this an modify it accordingly.
I also needed a way to update the stars after one was clicked in the NewForm or EditForm, or once an item was loaded in the DispForm or EditForm. This function handles the updates to the stars:
function updateStars(element, index) { element.querySelectorAll('.star').forEach((star, i) => { if (i < index) { star.classList.add('active'); } else { star.classList.remove('active'); } }); }Finally, all of this needed to be applied to the star-rating elements in the forms. For the NewForm I just needed a click handler. For the DispForm I just needed to update the stars based on the initial values. For the EditForm I needed to do both. Here is the code for each:
NewFormfunction formInitSetup() { /* Click handler for star ratings */ document.querySelectorAll('.star-rating').forEach(starRating => { // Get top level element for HTML section const htmlWrapElement = findHtmlWrap(starRating); // Get the internal field name for the related field const fieldInternalName = findFieldName(htmlWrapElement); starRating.addEventListener('click', (event) => { const index = parseInt(event.target.getAttribute('data-index')); // Update visual style of stars updateStars(starRating, index); // Update the value of the related field setFieldValue(fieldInternalName, index); }); }); }DispForm
function formInitSetup() { /* Get current values for star ratings */ document.querySelectorAll('.star-rating').forEach(starRating => { // Get top level element for HTML section const htmlWrapElement = findHtmlWrap(starRating); // Get the internal field name for the related field const fieldInternalName = findFieldName(htmlWrapElement); // Get the current field value const fieldValue = getFieldValue(fieldInternalName); // Update visual style of stars updateStars(starRating, fieldValue); }); }EditForm
function formInitSetup() { /* Click handler for star ratings */ document.querySelectorAll('.star-rating').forEach(starRating => { // Get top level element for HTML section const htmlWrapElement = findHtmlWrap(starRating); // Get the internal field name for the related field const fieldInternalName = findFieldName(htmlWrapElement); // Get the current field value const fieldValue = getFieldValue(fieldInternalName); // Update visual style of stars updateStars(starRating, fieldValue); starRating.addEventListener('click', (event) => { const index = parseInt(event.target.getAttribute('data-index')); // Update visual style of stars updateStars(starRating, index); // Update the value of the related field setFieldValue(fieldInternalName, index); }); }); }Rule
I used a rule to trigger the formInitSetup() function from Custom JavaScript when the form loads.Conclusion
I hope this is useful to someone. I felt like it would be a good idea to post this information on the forum for others, and also so I know it lives somewhere I can come back to if I forget what I did! 😉 Let me know if you found this helpful, or if you have questions about any part of it. -
August 26, 2025 at 21:12 #38865
Thanks for sharing, and for including all the detailed descriptions – this looks very nice!
Alexander
-
-
AuthorPosts
- You must be logged in to reply to this topic.


