diff --git a/docs/components/rating.md b/docs/components/rating.md
index 4a5784cb..f0e55a24 100644
--- a/docs/components/rating.md
+++ b/docs/components/rating.md
@@ -56,7 +56,7 @@ import { SlRating } from '@shoelace-style/shoelace/dist/react';
const App = () => ;
```
-## Symbol Sizes
+### Symbol Sizes
Set the `--symbol-size` custom property to adjust the size.
@@ -98,6 +98,99 @@ import { SlRating } from '@shoelace-style/shoelace/dist/react';
const App = () => ;
```
+### Detecting Hover
+
+Use the `sl-hover` event to detect when the user hovers over (or touch and drag) the rating. This lets you hook into values as the user interacts with the rating, but before they select a value.
+
+The event has a payload with `phase` and `value` properties. The `phase` property tells when hovering starts, moves to a new value, and ends. The `value` property tells what the rating's value would be if the user were to commit to the hovered value.
+
+```html preview
+
+
+
+
+
+
+
+
+```
+
+```jsx react
+import { useState } from 'react';
+import { SlRating } from '@shoelace-style/shoelace/dist/react';
+
+const terms = ['No rating', 'Terrible', 'Bad', 'OK', 'Good', 'Excellent'];
+const css = `
+ .detect-hover span {
+ position: relative;
+ top: -4px;
+ left: 8px;
+ border-radius: var(--sl-border-radius-small);
+ background: var(--sl-color-neutral-900);
+ color: var(--sl-color-neutral-0);
+ text-align: center;
+ padding: 4px 6px;
+ }
+
+ .detect-hover span:empty {
+ display: none;
+ }
+`;
+
+function handleHover(event) {
+ rating.addEventListener('sl-hover', event => {
+ setFeedback(terms[event.detail.value]);
+
+ // Clear feedback when hovering stops
+ if (event.detail.phase === 'end') {
+ setFeedback('');
+ }
+ });
+}
+
+const App = () => {
+ const [feedback, setFeedback] = useState(true);
+
+ return (
+ <>
+
+
+ {feedback}
+
+
+ >
+ );
+};
+```
+
### Custom Icons
You can provide custom icons by passing a function to the `getSymbol` property.
@@ -112,7 +205,6 @@ You can provide custom icons by passing a function to the `getSymbol` property.
```
```jsx react
-import '@shoelace-style/shoelace/dist/components/icon/icon';
import { SlRating } from '@shoelace-style/shoelace/dist/react';
const App = () => (
@@ -142,7 +234,6 @@ You can also use the `getSymbol` property to render different icons based on val
```
```jsx react
-import '@shoelace-style/shoelace/dist/components/icon/icon';
import { SlRating } from '@shoelace-style/shoelace/dist/react';
function getSymbol(value) {
diff --git a/docs/resources/changelog.md b/docs/resources/changelog.md
index 99fca445..40c545ba 100644
--- a/docs/resources/changelog.md
+++ b/docs/resources/changelog.md
@@ -12,6 +12,7 @@ New versions of Shoelace are released as-needed and generally occur when a criti
- Added support for the `inert` attribute on `` to allow hidden menu items to not accept focus [#1107](https://github.com/shoelace-style/shoelace/issues/1107)
- Added the `tag` part to ``
+- Added `sl-hover` event to `` [#1125](https://github.com/shoelace-style/shoelace/issues/1125)
- Fixed a bug in `` that prevented placeholders from showing when `multiple` was used [#1109](https://github.com/shoelace-style/shoelace/issues/1109)
- Fixed a bug in `` that caused tags to not be rounded when using the `pill` attribute [#1117](https://github.com/shoelace-style/shoelace/issues/1117)
- Fixed a bug in `` where the `sl-change` and `sl-input` events didn't weren't emitted when removing tags [#1119](https://github.com/shoelace-style/shoelace/issues/1119)
diff --git a/src/components/rating/rating.ts b/src/components/rating/rating.ts
index 64c8eb86..84e57ff1 100644
--- a/src/components/rating/rating.ts
+++ b/src/components/rating/rating.ts
@@ -5,6 +5,7 @@ import { styleMap } from 'lit/directives/style-map.js';
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
import { clamp } from '../../internal/math';
import ShoelaceElement from '../../internal/shoelace-element';
+import { watch } from '../../internal/watch';
import { LocalizeController } from '../../utilities/localize';
import '../icon/icon';
import styles from './rating.styles';
@@ -19,6 +20,9 @@ import type { CSSResultGroup } from 'lit';
* @dependency sl-icon
*
* @event sl-change - Emitted when the rating's value changes.
+ * @event {{ phase: 'start' | 'move' | 'end', value: number }} sl-hover - Emitted when the user hovers over a value. The
+ * `phase` property indicates when hovering starts, moves to a new value, or ends. The `value` property tells what the
+ * rating's value would be if the user were to commit to the hovered value.
*
* @csspart base - The component's base wrapper.
*
@@ -134,8 +138,9 @@ export default class SlRating extends ShoelaceElement {
}
}
- private handleMouseEnter() {
+ private handleMouseEnter(event: MouseEvent) {
this.isHovering = true;
+ this.hoverValue = this.getValueFromMousePosition(event);
}
private handleMouseMove(event: MouseEvent) {
@@ -147,6 +152,7 @@ export default class SlRating extends ShoelaceElement {
}
private handleTouchStart(event: TouchEvent) {
+ this.isHovering = true;
this.hoverValue = this.getValueFromTouchPosition(event);
// Prevent scrolling when touch is initiated
@@ -154,7 +160,6 @@ export default class SlRating extends ShoelaceElement {
}
private handleTouchMove(event: TouchEvent) {
- this.isHovering = true;
this.hoverValue = this.getValueFromTouchPosition(event);
}
@@ -172,6 +177,26 @@ export default class SlRating extends ShoelaceElement {
return Math.ceil(numberToRound * multiplier) / multiplier;
}
+ @watch('hoverValue')
+ handleHoverValueChange() {
+ this.emit('sl-hover', {
+ detail: {
+ phase: 'move',
+ value: this.hoverValue
+ }
+ });
+ }
+
+ @watch('isHovering')
+ handleIsHoveringChange() {
+ this.emit('sl-hover', {
+ detail: {
+ phase: this.isHovering ? 'start' : 'end',
+ value: this.hoverValue
+ }
+ });
+ }
+
/** Sets focus on the rating. */
focus(options?: FocusOptions) {
this.rating.focus(options);