InputRating

RatingGitHub
A component to display and collect ratings from users.

Usage

Use the v-model directive to control the rating value of the InputRating component.

<script setup lang="ts">
const value = ref(3)
</script>

<template>
  <PInputRating v-model="value" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const value = ref(3)
</script>

<template>
  <PInputRating v-model="value" />
</template>

Use the default-value prop to set the initial value when you do not need to control its state.

<template>
  <PInputRating :default-value="3" />
</template>

Step

Use the step prop to control the granularity of each star. Set it to 0.5 to allow half-star ratings.

<template>
  <PInputRating :step="0.5" :default-value="3.5" />
</template>

Length

Use the length prop to set the number of stars. Defaults to 5.

<template>
  <PInputRating :length="10" :step="0.5" :default-value="7.5" />
</template>

Clearable

Use the clearable prop to allow users to clear the rating by clicking on the currently selected value. Defaults to false.

<template>
  <PInputRating clearable :default-value="3" />
</template>

Hoverable

Use the hoverable prop to control whether the rating previews the value when hovering over the stars. Defaults to false.

<template>
  <PInputRating hoverable :default-value="3" />
</template>

Icon

Use the icon prop to customize the icon used for stars. Defaults to i-lucide-star.

<template>
  <PInputRating icon="i-lucide-heart" :default-value="4" />
</template>
You can customize the default star icon globally in your app.config.ts under ui.icons.star key.
You can customize the default star icon globally in your vite.config.ts under ui.icons.star key.

Empty Icon

Use the empty-icon prop to customize the icon used for empty stars. If not provided, uses the same icon as icon.

<template>
  <PInputRating empty-icon="i-lucide-circle" icon="i-lucide-circle-check" :default-value="3" />
</template>

Color

Use the color prop to change the color of the filled stars.

<template>
  <PInputRating color="neutral" :default-value="4" />
</template>

Size

Use the size prop to change the size of the stars.

<template>
  <PInputRating size="xl" :default-value="4" />
</template>

Orientation

Use the orientation prop to change the orientation of the rating. Defaults to horizontal.

<template>
  <PInputRating orientation="vertical" :default-value="4" />
</template>

Disabled

Use the disabled prop to disable the InputRating component. When disabled, the component has reduced opacity (75%) and shows a not-allowed cursor to indicate it's not interactive.

<template>
  <PInputRating disabled :default-value="3" />
</template>

Readonly

Use the readonly prop to display a rating without allowing user interaction. Unlike disabled, it maintains normal appearance (full opacity, default cursor). Use when you want to display a rating that cannot be changed but should look normal.

<template>
  <PInputRating readonly :default-value="4.5" />
</template>

API

Props

Prop Default Type
as
'div'
any

The element or component this component should render as.

id
string

The id of the rating.

readonly
false
boolean

Make the rating readonly (non-interactive).

icon
appConfig.ui.icons.star
any

The icon displayed for each rating value.

emptyIcon
any

The icon displayed for empty rating values. Defaults to icon when not provided.

color
'primary'
"primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral"
size
'md'
"md" | "xs" | "sm" | "lg" | "xl"
orientation
'horizontal'
"horizontal" | "vertical"

The orientation of the rating.

length
number

The number of rating items to render.

step
1 | 0.5 | 0.25 | 0.1

The granularity each rating item is divided into.

name
string

The name of the field. Submitted with its owning form as part of a name/value pair.

disabled
boolean

When true, prevents the user from interacting with radio items.

required
boolean

When true, indicates that the user must set the value before the owning form can be submitted.

clearable
boolean

When true, clicking the currently selected rating resets the value to 0.

hoverable
boolean

When true, the rating previews the value under the pointer on hover.

modelValue
number

The controlled rating value. Can be bound with v-model.

defaultValue
number

The rating value when initially rendered. Use when you do not need to control the state of the rating.

ui
{ root?: SlotClass; item?: SlotClass; indicator?: SlotClass; icon?: SlotClass; emptyIcon?: SlotClass; }

Slots

Slot Type
item
{ index: number; filled: boolean; }

Rendered for each item. filled is false for the empty background layer and true for the highlighted overlay.

Emits

Event Type
change
[event: Event]
update:modelValue
[payload: number]

Theme

app.config.ts
export default defineAppConfig({
  ui: {
    inputRating: {
      slots: {
        root: '',
        item: [
          'relative inline-block cursor-pointer select-none rounded-sm has-focus-visible:outline-3',
          'transition'
        ],
        indicator: 'text-transparent outline-none opacity-$akar-rating-item-step-opacity w-$akar-rating-item-step-width inset-0 absolute z-$akar-rating-item-step-z-index overflow-hidden',
        icon: 'block',
        emptyIcon: 'block w-full h-full color-text-muted pointer-events-none'
      },
      variants: {
        orientation: {
          horizontal: {
            root: 'inline-flex items-center gap-0.5'
          },
          vertical: {
            root: 'inline-flex flex-col items-center gap-0.5'
          }
        },
        size: {
          xs: {
            item: 'size-3',
            icon: 'size-3'
          },
          sm: {
            item: 'size-4',
            icon: 'size-4'
          },
          md: {
            item: 'size-5',
            icon: 'size-5'
          },
          lg: {
            item: 'size-6',
            icon: 'size-6'
          },
          xl: {
            item: 'size-7',
            icon: 'size-7'
          }
        },
        color: {
          primary: {
            indicator: 'data-[state=active]:color-primary',
            item: 'outline-primary/25'
          },
          secondary: {
            indicator: 'data-[state=active]:color-secondary',
            item: 'outline-secondary/25'
          },
          success: {
            indicator: 'data-[state=active]:color-success',
            item: 'outline-success/25'
          },
          info: {
            indicator: 'data-[state=active]:color-info',
            item: 'outline-info/25'
          },
          warning: {
            indicator: 'data-[state=active]:color-warning',
            item: 'outline-warning/25'
          },
          error: {
            indicator: 'data-[state=active]:color-error',
            item: 'outline-error/25'
          },
          neutral: {
            indicator: 'data-[state=active]:color-text-highlighted',
            item: 'outline-border-inverted/25'
          }
        },
        readonly: {
          true: {
            root: 'cursor-default',
            item: 'cursor-default'
          },
          false: {}
        },
        disabled: {
          true: {
            root: 'opacity-75 cursor-not-allowed',
            item: 'cursor-not-allowed pointer-events-none'
          },
          false: {}
        }
      },
      compoundVariants: [
        {
          readonly: false,
          disabled: false,
          class: {
            item: 'hover:scale-110'
          }
        }
      ],
      defaultVariants: {
        color: 'primary',
        size: 'md'
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from 'pohon-ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        inputRating: {
          slots: {
            root: '',
            item: [
              'relative inline-block cursor-pointer select-none rounded-sm has-focus-visible:outline-3',
              'transition'
            ],
            indicator: 'text-transparent outline-none opacity-$akar-rating-item-step-opacity w-$akar-rating-item-step-width inset-0 absolute z-$akar-rating-item-step-z-index overflow-hidden',
            icon: 'block',
            emptyIcon: 'block w-full h-full color-text-muted pointer-events-none'
          },
          variants: {
            orientation: {
              horizontal: {
                root: 'inline-flex items-center gap-0.5'
              },
              vertical: {
                root: 'inline-flex flex-col items-center gap-0.5'
              }
            },
            size: {
              xs: {
                item: 'size-3',
                icon: 'size-3'
              },
              sm: {
                item: 'size-4',
                icon: 'size-4'
              },
              md: {
                item: 'size-5',
                icon: 'size-5'
              },
              lg: {
                item: 'size-6',
                icon: 'size-6'
              },
              xl: {
                item: 'size-7',
                icon: 'size-7'
              }
            },
            color: {
              primary: {
                indicator: 'data-[state=active]:color-primary',
                item: 'outline-primary/25'
              },
              secondary: {
                indicator: 'data-[state=active]:color-secondary',
                item: 'outline-secondary/25'
              },
              success: {
                indicator: 'data-[state=active]:color-success',
                item: 'outline-success/25'
              },
              info: {
                indicator: 'data-[state=active]:color-info',
                item: 'outline-info/25'
              },
              warning: {
                indicator: 'data-[state=active]:color-warning',
                item: 'outline-warning/25'
              },
              error: {
                indicator: 'data-[state=active]:color-error',
                item: 'outline-error/25'
              },
              neutral: {
                indicator: 'data-[state=active]:color-text-highlighted',
                item: 'outline-border-inverted/25'
              }
            },
            readonly: {
              true: {
                root: 'cursor-default',
                item: 'cursor-default'
              },
              false: {}
            },
            disabled: {
              true: {
                root: 'opacity-75 cursor-not-allowed',
                item: 'cursor-not-allowed pointer-events-none'
              },
              false: {}
            }
          },
          compoundVariants: [
            {
              readonly: false,
              disabled: false,
              class: {
                item: 'hover:scale-110'
              }
            }
          ],
          defaultVariants: {
            color: 'primary',
            size: 'md'
          }
        }
      }
    })
  ]
})

Changelog

No recent changes