diff --git a/docs/content/3.components/rating.md b/docs/content/3.components/rating.md
new file mode 100644
index 0000000000..867ceb3f50
--- /dev/null
+++ b/docs/content/3.components/rating.md
@@ -0,0 +1,33 @@
+---
+title: Rating
+description: ''
+links:
+ - label: Rating
+ icon: i-custom-reka-ui
+ to: https://reka-ui.com/docs/components/rating
+ - label: GitHub
+ icon: i-simple-icons-github
+ to: https://github.com/nuxt/ui/tree/v3/src/runtime/components/Rating.vue
+---
+
+## Usage
+
+## Examples
+
+## API
+
+### Props
+
+:component-props
+
+### Slots
+
+:component-slots
+
+### Emits
+
+:component-emits
+
+## Theme
+
+:component-theme
diff --git a/playground/app/pages/components/rating.vue b/playground/app/pages/components/rating.vue
new file mode 100644
index 0000000000..26607f973d
--- /dev/null
+++ b/playground/app/pages/components/rating.vue
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
diff --git a/src/runtime/components/Rating.vue b/src/runtime/components/Rating.vue
new file mode 100644
index 0000000000..6bb7263a4e
--- /dev/null
+++ b/src/runtime/components/Rating.vue
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/runtime/types/index.ts b/src/runtime/types/index.ts
index c5e73f665b..aaba397e7f 100644
--- a/src/runtime/types/index.ts
+++ b/src/runtime/types/index.ts
@@ -35,6 +35,7 @@ export * from '../components/PinInput.vue'
export * from '../components/Popover.vue'
export * from '../components/Progress.vue'
export * from '../components/RadioGroup.vue'
+export * from '../components/Rating.vue'
export * from '../components/Select.vue'
export * from '../components/SelectMenu.vue'
export * from '../components/Separator.vue'
diff --git a/src/theme/index.ts b/src/theme/index.ts
index 752065ec45..b5adf51581 100644
--- a/src/theme/index.ts
+++ b/src/theme/index.ts
@@ -33,6 +33,7 @@ export { default as pinInput } from './pin-input'
export { default as popover } from './popover'
export { default as progress } from './progress'
export { default as radioGroup } from './radio-group'
+export { default as rating } from './rating'
export { default as select } from './select'
export { default as selectMenu } from './select-menu'
export { default as separator } from './separator'
diff --git a/src/theme/rating.ts b/src/theme/rating.ts
new file mode 100644
index 0000000000..9ccd648a75
--- /dev/null
+++ b/src/theme/rating.ts
@@ -0,0 +1,21 @@
+export default {
+ slots: {
+ root: 'space-x-1 flex items-center',
+ icon: 'data-[state=active]:text-yellow-500'
+ },
+
+ variants: {
+ orientation: {
+ horizontal: {
+ root: ''
+ },
+ vertical: {
+ root: 'flex-col'
+ }
+ }
+ },
+
+ defaultVariants: {
+ orientation: 'horizontal'
+ }
+}
diff --git a/test/components/Rating.spec.ts b/test/components/Rating.spec.ts
new file mode 100644
index 0000000000..0137208bee
--- /dev/null
+++ b/test/components/Rating.spec.ts
@@ -0,0 +1,17 @@
+import { describe, it, expect } from 'vitest'
+import Rating, { type RatingProps, type RatingSlots } from '../../src/runtime/components/Rating.vue'
+import ComponentRender from '../component-render'
+
+describe('Rating', () => {
+ it.each([
+ // Props
+ ['with as', { props: { as: 'section' } }],
+ ['with class', { props: { class: '' } }],
+ ['with ui', { props: { ui: {} } }],
+ // Slots
+ ['with default slot', { slots: { default: () => 'Default slot' } }]
+ ])('renders %s correctly', async (nameOrHtml: string, options: { props?: RatingProps, slots?: Partial }) => {
+ const html = await ComponentRender(nameOrHtml, options, Rating)
+ expect(html).toMatchSnapshot()
+ })
+})