diff --git a/frontend/e2e/specs/rating-field.spec.ts b/frontend/e2e/specs/rating-field.spec.ts
new file mode 100644
index 0000000..9f94d8f
--- /dev/null
+++ b/frontend/e2e/specs/rating-field.spec.ts
@@ -0,0 +1,78 @@
+import { test, expect } from "../fixtures/test-data.fixture";
+import { SubmissionPage } from "../helpers/submission";
+
+test.describe("Rating field", () => {
+ test("retains the value the user clicked (no clamp to 1.0)", async ({
+ browser,
+ createPublishedForm,
+ apiContext,
+ }) => {
+ const { formId, route } = await createPublishedForm();
+
+ // Add a Rating field to the published form via REST
+ const formRes = await apiContext.get(`/api/resource/Form/${formId}`);
+ const { data: formData } = await formRes.json();
+ const linkedDoctype: string = formData.linked_doctype;
+ const ratingFieldname = "satisfaction";
+
+ await apiContext.put(`/api/resource/Form/${formId}`, {
+ data: {
+ fields: [
+ ...(formData.fields ?? []),
+ {
+ fieldtype: "Rating",
+ label: "Satisfaction",
+ fieldname: ratingFieldname,
+ reqd: 0,
+ },
+ ],
+ },
+ });
+
+ // Guest fills + submits the form
+ const guestCtx = await browser.newContext();
+ const guestPage = await guestCtx.newPage();
+ const submissionPage = new SubmissionPage(guestPage);
+ await submissionPage.goto(route);
+
+ await expect(guestPage.getByRole("button", { name: "Submit" })).toBeVisible(
+ { timeout: 10000 }
+ );
+
+ // Click the 3rd star (1-indexed → nth(2)). feather-icons stamps the class.
+ const stars = guestPage.locator("svg.feather-star");
+ await expect(stars).toHaveCount(5);
+ await stars.nth(2).click();
+
+ await submissionPage.submit();
+ await expect(submissionPage.successMessage()).toBeVisible({
+ timeout: 10000,
+ });
+
+ await guestCtx.close();
+
+ // Fetch the submission record via REST and assert the stored value.
+ // Frappe stores Rating as a 0..1 fraction → 3/5 == 0.6.
+ const listRes = await apiContext.get(
+ `/api/resource/${encodeURIComponent(linkedDoctype)}`,
+ {
+ params: {
+ filters: JSON.stringify([["fp_linked_form", "=", formId]]),
+ fields: JSON.stringify(["name"]),
+ limit_page_length: 1,
+ },
+ }
+ );
+ const { data: list } = await listRes.json();
+ expect(list).toHaveLength(1);
+ const submissionName = list[0].name;
+
+ const getRes = await apiContext.get(
+ `/api/resource/${encodeURIComponent(linkedDoctype)}/${encodeURIComponent(
+ submissionName
+ )}`
+ );
+ const { data: submission } = await getRes.json();
+ expect(submission[ratingFieldname]).toBeCloseTo(0.6, 5);
+ });
+});
diff --git a/frontend/src/components/fields/Rating.vue b/frontend/src/components/fields/Rating.vue
new file mode 100644
index 0000000..5b006b8
--- /dev/null
+++ b/frontend/src/components/fields/Rating.vue
@@ -0,0 +1,34 @@
+
+
+
+
+
diff --git a/frontend/src/components/form/submissions/SubmissionFieldValue.vue b/frontend/src/components/form/submissions/SubmissionFieldValue.vue
index 9e0adcf..dcbb56f 100644
--- a/frontend/src/components/form/submissions/SubmissionFieldValue.vue
+++ b/frontend/src/components/form/submissions/SubmissionFieldValue.vue
@@ -100,7 +100,12 @@ const classNames = computed(() =>
editorClass="prose-sm !border-none !p-0 !shadow-none"
/>
-
+