Closed HenryWu01 closed 7 months ago
Hello @HenryWu01, Thank you for your inquiry. By default, Rating Scale displays item captions in a tooltip. If you wish to display an item's text underneath the item, you can implement a custom item template for a Rating question and display the value under the rate item. An example is available at Rating Scale: Custom Item Component Support.
You can implement a custom rate item component on top of a default template and display a value label under the rate item.
Consider the following demo: View Stackblitz.
App.js
import React from 'react';
import './style.css';
import { Model } from 'survey-core';
import { Survey } from 'survey-react-ui';
import 'survey-core/defaultV2.min.css';
import { json } from './json';
import { SvgRegistry } from 'survey-core';
import {
ReactElementFactory,
SurveyElementBase,
SvgIcon,
} from 'survey-react-ui';
class CustomChoiceItem extends SurveyElementBase {
renderElement() {
const question = this.props.question;
const item = this.props.item;
const isDisplayMode = this.isDisplayMode;
const handleOnClick = this.props.handleOnClick;
const handleOnMouseDown = this.props.handleOnMouseDown;
const index = this.props.index;
return (
<label
onMouseDown={handleOnMouseDown}
className={`${question.getItemClass(item.itemValue)} outer-label`}
onMouseOver={(e) => question.onItemMouseIn(item)}
onMouseOut={(e) => question.onItemMouseOut(item)}
>
<input
type="radio"
className="sv-visuallyhidden"
name={question.name}
id={question.getInputId(index)}
value={item.value}
disabled={isDisplayMode}
checked={question.value == item.value}
onClick={handleOnClick}
onChange={() => {}}
aria-required={question.ariaRequired}
aria-label={question.ariaLabel}
aria-invalid={question.ariaInvalid}
aria-describedby={question.ariaDescribedBy}
/>
<SvgIcon
className={'sv-star'}
size={'auto'}
iconName={question.itemStarIcon}
title={item.text}
></SvgIcon>
<SvgIcon
className={'sv-star-2'}
size={'auto'}
iconName={question.itemStarIconAlt}
title={item.text}
></SvgIcon>
<label className={'caption'}>{item.text}</label>
</label>
);
}
}
ReactElementFactory.Instance.registerElement('custom-rate-item', (props) => {
return React.createElement(CustomChoiceItem, props);
});
export default function App() {
const survey = new Model(json);
survey.onComplete.add((sender, options) => {
console.log(JSON.stringify(sender.data, null, 3));
});
return <Survey model={survey} />;
}
style.css
.caption {
margin-top: 50px;
}
.outer-label {
display: flex;
flex-direction: column;
align-items: center;
}
json.js
export const json = {
elements: [
{
type: 'rating',
name: 'satisfaction-smileys-colored',
title: 'How satisfied are you with our product?',
description: 'Smiley rating with colored scale',
rateType: 'stars',
scaleColorMode: 'colored',
autoGenerate: false,
rateValues: [
{
value: 1,
text: 'Terrible',
},
{
value: 2,
text: 'Poor',
},
{
value: 3,
text: 'Average',
},
{
value: 4,
text: 'Good',
},
{
value: 5,
text: 'Perfect',
},
],
displayMode: 'buttons',
itemComponent: 'custom-rate-item',
},
],
showQuestionNumbers: false,
};
Please drop me a line if you have further questions.
A similar issue was also discussed at https://surveyjs.answerdesk.io/ticket/details/T15178.
Hello @HenryWu01, Thank you for your inquiry. By default, Rating Scale displays item captions in a tooltip. If you wish to display an item's text underneath the item, you can implement a custom item template for a Rating question and display the value under the rate item. An example is available at Rating Scale: Custom Item Component Support.
You can implement a custom rate item component on top of a default template and display a value label under the rate item.
Consider the following demo: View Stackblitz.
App.js
import React from 'react'; import './style.css'; import { Model } from 'survey-core'; import { Survey } from 'survey-react-ui'; import 'survey-core/defaultV2.min.css'; import { json } from './json'; import { SvgRegistry } from 'survey-core'; import { ReactElementFactory, SurveyElementBase, SvgIcon, } from 'survey-react-ui'; class CustomChoiceItem extends SurveyElementBase { renderElement() { const question = this.props.question; const item = this.props.item; const isDisplayMode = this.isDisplayMode; const handleOnClick = this.props.handleOnClick; const handleOnMouseDown = this.props.handleOnMouseDown; const index = this.props.index; return ( <label onMouseDown={handleOnMouseDown} className={`${question.getItemClass(item.itemValue)} outer-label`} onMouseOver={(e) => question.onItemMouseIn(item)} onMouseOut={(e) => question.onItemMouseOut(item)} > <input type="radio" className="sv-visuallyhidden" name={question.name} id={question.getInputId(index)} value={item.value} disabled={isDisplayMode} checked={question.value == item.value} onClick={handleOnClick} onChange={() => {}} aria-required={question.ariaRequired} aria-label={question.ariaLabel} aria-invalid={question.ariaInvalid} aria-describedby={question.ariaDescribedBy} /> <SvgIcon className={'sv-star'} size={'auto'} iconName={question.itemStarIcon} title={item.text} ></SvgIcon> <SvgIcon className={'sv-star-2'} size={'auto'} iconName={question.itemStarIconAlt} title={item.text} ></SvgIcon> <label className={'caption'}>{item.text}</label> </label> ); } } ReactElementFactory.Instance.registerElement('custom-rate-item', (props) => { return React.createElement(CustomChoiceItem, props); }); export default function App() { const survey = new Model(json); survey.onComplete.add((sender, options) => { console.log(JSON.stringify(sender.data, null, 3)); }); return <Survey model={survey} />; }
style.css
.caption { margin-top: 50px; } .outer-label { display: flex; flex-direction: column; align-items: center; }
json.js
export const json = { elements: [ { type: 'rating', name: 'satisfaction-smileys-colored', title: 'How satisfied are you with our product?', description: 'Smiley rating with colored scale', rateType: 'stars', scaleColorMode: 'colored', autoGenerate: false, rateValues: [ { value: 1, text: 'Terrible', }, { value: 2, text: 'Poor', }, { value: 3, text: 'Average', }, { value: 4, text: 'Good', }, { value: 5, text: 'Perfect', }, ], displayMode: 'buttons', itemComponent: 'custom-rate-item', }, ], showQuestionNumbers: false, };
Please drop me a line if you have further questions.
A similar issue was also discussed at https://surveyjs.answerdesk.io/ticket/details/T15178.
Thank you for the quick response. May I ask that how does the margin-top: 50px;
calculated from? Can we wrap the SvgIcon
and input
inside a div
?
Hello @HenryWu01,
May I ask that how does the margin-top: 50px; calculated from?
This value is hardcoded within CSS. You may wish to calculate this value depending on a survey's base unit. With this option, a top margin will be adjusted depending on the --sjs-base-unit
value defined within a survcey theme. I updated the demo: View Stackblitz.
Can we wrap the SvgIcon and input inside a div?
You can update a custom item component as needed as long as the custom template produces the target output.
Please feel free to reopen this thread if you have any further questions.
We discussed this case and decided not to implement it out-of-the-box and reccomended to use the code above.
Are you requesting a feature, reporting a bug or asking a question?
Feature Request
What is the current behavior?
We can only set the description for min value and max value.
What is the expected behavior?
We can set the description for every rating value.
How would you reproduce the current behavior (if this is a bug)?
Provide the test code and the tested page URL (if applicable)
Tested page URL:
Test code
Specify your