diff --git a/app/assets/javascripts/discourse/app/components/user-flag-percentage.gjs b/app/assets/javascripts/discourse/app/components/user-flag-percentage.gjs
new file mode 100644
index 00000000000..f362ff925e8
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/components/user-flag-percentage.gjs
@@ -0,0 +1,64 @@
+import Component from "@glimmer/component";
+import { cached } from "@glimmer/tracking";
+import { gte } from "truth-helpers";
+import icon from "discourse-common/helpers/d-icon";
+import { i18n } from "discourse-i18n";
+
+export default class UserFlagPercentage extends Component {
+  // We do a little logic to choose which icon to display and which text
+  @cached
+  get percentage() {
+    const { agreed, disagreed, ignored } = this.args;
+    const total = agreed + disagreed + ignored;
+    const result = { total };
+
+    if (total <= 0) {
+      return result;
+    }
+
+    const roundedAgreed = Math.round((agreed / total) * 100);
+    const roundedDisagreed = Math.round((disagreed / total) * 100);
+    const roundedIgnored = Math.round((ignored / total) * 100);
+
+    const highest = Math.max(agreed, disagreed, ignored);
+    if (highest === agreed) {
+      result.icon = "thumbs-up";
+      result.className = "agreed";
+      result.label = `${roundedAgreed}%`;
+    } else if (highest === disagreed) {
+      result.icon = "thumbs-down";
+      result.className = "disagreed";
+      result.label = `${roundedDisagreed}%`;
+    } else {
+      result.icon = "up-right-from-square";
+      result.className = "ignored";
+      result.label = `${roundedIgnored}%`;
+    }
+
+    result.title = i18n("review.user_percentage.summary", {
+      agreed: i18n("review.user_percentage.agreed", {
+        count: roundedAgreed,
+      }),
+      disagreed: i18n("review.user_percentage.disagreed", {
+        count: roundedDisagreed,
+      }),
+      ignored: i18n("review.user_percentage.ignored", {
+        count: roundedIgnored,
+      }),
+      count: total,
+    });
+
+    return result;
+  }
+
+  <template>
+    {{#if (gte this.percentage.total 3)}}
+      <div title={{this.percentage.title}} class="user-flag-percentage">
+        <span
+          class="percentage-label {{this.percentage.className}}"
+        >{{this.percentage.label}}</span>
+        {{icon this.percentage.icon}}
+      </div>
+    {{/if}}
+  </template>
+}
diff --git a/app/assets/javascripts/discourse/app/components/user-flag-percentage.hbs b/app/assets/javascripts/discourse/app/components/user-flag-percentage.hbs
deleted file mode 100644
index dfb33468822..00000000000
--- a/app/assets/javascripts/discourse/app/components/user-flag-percentage.hbs
+++ /dev/null
@@ -1,8 +0,0 @@
-{{#if this.showPercentage}}
-  <div title={{this.percentage.title}} class="user-flag-percentage">
-    <span
-      class="percentage-label {{this.percentage.className}}"
-    >{{this.percentage.label}}</span>
-    {{d-icon this.percentage.icon}}
-  </div>
-{{/if}}
\ No newline at end of file
diff --git a/app/assets/javascripts/discourse/app/components/user-flag-percentage.js b/app/assets/javascripts/discourse/app/components/user-flag-percentage.js
deleted file mode 100644
index 93f8c2ec3a0..00000000000
--- a/app/assets/javascripts/discourse/app/components/user-flag-percentage.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import Component from "@ember/component";
-import { tagName } from "@ember-decorators/component";
-import discourseComputed from "discourse-common/utils/decorators";
-import { i18n } from "discourse-i18n";
-
-@tagName("")
-export default class UserFlagPercentage extends Component {
-  @discourseComputed("percentage")
-  showPercentage(percentage) {
-    return percentage.total >= 3;
-  }
-
-  // We do a little logic to choose which icon to display and which text
-  @discourseComputed("agreed", "disagreed", "ignored")
-  percentage(agreed, disagreed, ignored) {
-    let total = agreed + disagreed + ignored;
-    let result = { total };
-
-    if (total > 0) {
-      result.agreed = Math.round((agreed / total) * 100);
-      result.disagreed = Math.round((disagreed / total) * 100);
-      result.ignored = Math.round((ignored / total) * 100);
-    }
-
-    let highest = Math.max(agreed, disagreed, ignored);
-    if (highest === agreed) {
-      result.icon = "thumbs-up";
-      result.className = "agreed";
-      result.label = `${result.agreed}%`;
-    } else if (highest === disagreed) {
-      result.icon = "thumbs-down";
-      result.className = "disagreed";
-      result.label = `${result.disagreed}%`;
-    } else {
-      result.icon = "up-right-from-square";
-      result.className = "ignored";
-      result.label = `${result.ignored}%`;
-    }
-
-    result.title = i18n("review.user_percentage.summary", {
-      agreed: i18n("review.user_percentage.agreed", {
-        count: result.agreed,
-      }),
-      disagreed: i18n("review.user_percentage.disagreed", {
-        count: result.disagreed,
-      }),
-      ignored: i18n("review.user_percentage.ignored", {
-        count: result.ignored,
-      }),
-      count: total,
-    });
-
-    return result;
-  }
-}