diff --git a/continue.md b/continue.md
index 4e46f2e2b..3d5be4875 100644
--- a/continue.md
+++ b/continue.md
@@ -58,9 +58,20 @@ Actualizacion Eidos component migration 2026-05-17:
- `npm run check` -> 0 errores, 0 warnings.
- `node --import tsx/esm scripts/eidos-lint-all.ts` -> 0 invalid, sin drift
hotspots.
+- Cuarta tanda del mismo bloque:
+ - `RatingGroup`: root visual `rating-group.svelte`, parte `Item`,
+ `rating-group.css`, `types.ts` e `index.ts`.
+ - No se inventa icono/star por defecto ni API nueva; el wrapper conserva los
+ snippets de Soma (`items` en root y `state` en item) y la receta estiliza
+ `active`, `partial`, `inactive`, foco, vertical/horizontal y disabled.
+- Validado despues de `RatingGroup`:
+ - `npx vitest run src/uix/eidos` -> 7 archivos, 84 tests OK.
+ - `npm run check` -> 0 errores, 0 warnings.
+ - `node --import tsx/esm scripts/eidos-lint-all.ts` -> 0 invalid, sin drift
+ hotspots.
- Siguiente bloque sugerido:
- Migrar otro grupo de bajo riesgo desde Soma a Eidos: candidatos reales por
- morfo/soma existentes son `rating-group` o `number-field`.
+ morfo/soma existentes son `number-field`, `field` o `search-field`.
- Antes de tocar componentes grandes (`select`, `combobox`, `calendar`,
`date-field`) conviene fijar una tabla por componente: partes Soma,
props visuales Eidos, recipe tokens y attrs esperados.
diff --git a/src/uix/eidos/component-visual-attrs.test.ts b/src/uix/eidos/component-visual-attrs.test.ts
index 68a82e093..80ade6e26 100644
--- a/src/uix/eidos/component-visual-attrs.test.ts
+++ b/src/uix/eidos/component-visual-attrs.test.ts
@@ -22,6 +22,7 @@ const VISUAL_ATTRS = [
['popover/popover-content.svelte', ['data-size']],
['progress/progress.svelte', ['data-size']],
['radio-group/radio-group.svelte', ['data-size', 'data-variant', 'data-color', 'data-columns']],
+ ['rating-group/rating-group.svelte', ['data-size']],
['slider/slider.svelte', ['data-size']],
['switch/switch.svelte', ['data-size']],
['tabs/tabs.svelte', ['data-size', 'data-variant', 'data-fitted', 'data-collapsed', 'data-motion']],
diff --git a/src/uix/eidos/components/README.md b/src/uix/eidos/components/README.md
index 81f5a40b8..bee50f19e 100644
--- a/src/uix/eidos/components/README.md
+++ b/src/uix/eidos/components/README.md
@@ -357,6 +357,7 @@ su subdirectorio.
| meter | ✅ multi-part | Indicator |
| pagination | ✅ multi-part | PrevTrigger, NextTrigger, Item, Ellipsis |
| progress | ✅ multi-part | Indicator |
+| rating-group | ✅ multi-part | Item |
| slider | ✅ multi-part | Range, Thumb, Tick |
| tooltip | ✅ multi-part | + Group |
| tabs | ✅ multi-part | List, Trigger, Content, Indicator |
diff --git a/src/uix/eidos/components/rating-group/index.ts b/src/uix/eidos/components/rating-group/index.ts
new file mode 100644
index 000000000..1a58f6d86
--- /dev/null
+++ b/src/uix/eidos/components/rating-group/index.ts
@@ -0,0 +1,32 @@
+// RatingGroup — eidos compound API, disciplined option C.
+//
+// import { RatingGroup } from '$uix/eidos/components/rating-group';
+//
+//
+// {#each items as item}
+// ★
+// {/each}
+//
+import RatingGroupRoot from './rating-group.svelte';
+import Item from './rating-group-item.svelte';
+
+type RatingGroupNamespace = typeof RatingGroupRoot & {
+ Item: typeof Item;
+};
+
+const RatingGroup = RatingGroupRoot as RatingGroupNamespace;
+RatingGroup.Item = Item;
+
+export { RatingGroup };
+
+export default RatingGroup;
+
+export type {
+ RatingGroupProps,
+ RatingGroupItemProps as ItemProps,
+ RatingGroupSize,
+ RatingGroupProviderSnippetProps as ProviderSnippetProps,
+ RatingGroupItemSnippetProps as ItemSnippetProps,
+ RatingItemDescriptor,
+ RatingItemState
+} from './types';
diff --git a/src/uix/eidos/components/rating-group/rating-group-item.svelte b/src/uix/eidos/components/rating-group/rating-group-item.svelte
new file mode 100644
index 000000000..4b45a0fea
--- /dev/null
+++ b/src/uix/eidos/components/rating-group/rating-group-item.svelte
@@ -0,0 +1,12 @@
+
+
+
+ {#snippet children(snippetProps)}
+ {@render children?.(snippetProps)}
+ {/snippet}
+
diff --git a/src/uix/eidos/components/rating-group/rating-group.css b/src/uix/eidos/components/rating-group/rating-group.css
new file mode 100644
index 000000000..e5318c08b
--- /dev/null
+++ b/src/uix/eidos/components/rating-group/rating-group.css
@@ -0,0 +1,83 @@
+[data-rating-group] {
+ --_rating-group-gap: var(--rating-group-gap-md);
+ --_rating-group-item-size: var(--rating-group-item-size-md);
+ --_rating-group-font-size: var(--rating-group-font-size-md);
+
+ display: inline-flex;
+ align-items: center;
+ gap: var(--_rating-group-gap);
+ color: var(--rating-group-item-color-inactive);
+ font-family: var(--rating-group-font-family);
+ font-size: var(--_rating-group-font-size);
+ line-height: var(--rating-group-line-height);
+ outline: none;
+}
+
+[data-rating-group][data-size='sm'] {
+ --_rating-group-gap: var(--rating-group-gap-sm);
+ --_rating-group-item-size: var(--rating-group-item-size-sm);
+ --_rating-group-font-size: var(--rating-group-font-size-sm);
+}
+
+[data-rating-group][data-size='lg'] {
+ --_rating-group-gap: var(--rating-group-gap-lg);
+ --_rating-group-item-size: var(--rating-group-item-size-lg);
+ --_rating-group-font-size: var(--rating-group-font-size-lg);
+}
+
+[data-rating-group][data-orientation='vertical'] {
+ flex-direction: column;
+ align-items: flex-start;
+}
+
+[data-rating-group]:focus-visible {
+ border-radius: var(--rating-group-focus-radius);
+ box-shadow: var(--rating-group-focus-shadow);
+}
+
+[data-rating-group][data-disabled] {
+ opacity: var(--rating-group-disabled-opacity);
+}
+
+[data-rating-group-item] {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ inline-size: var(--_rating-group-item-size);
+ block-size: var(--_rating-group-item-size);
+ color: var(--rating-group-item-color-inactive);
+ cursor: pointer;
+ transition:
+ color var(--rating-group-transition-duration) var(--rating-group-transition-ease),
+ transform var(--rating-group-transition-duration) var(--rating-group-transition-ease);
+}
+
+[data-rating-group-item][data-state='active'] {
+ color: var(--rating-group-item-color-active);
+}
+
+[data-rating-group-item][data-state='partial'] {
+ color: var(--rating-group-item-color-partial);
+}
+
+[data-rating-group-item]:hover:not([data-disabled]):not([data-readonly]) {
+ transform: translateY(var(--rating-group-item-hover-offset));
+}
+
+[data-rating-group-item][data-disabled],
+[data-rating-group-item][data-readonly] {
+ cursor: default;
+}
+
+[data-rating-group-item] > :where(svg) {
+ inline-size: 100%;
+ block-size: 100%;
+ fill: currentColor;
+ stroke: currentColor;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ [data-rating-group-item] {
+ transition: none;
+ }
+}
diff --git a/src/uix/eidos/components/rating-group/rating-group.svelte b/src/uix/eidos/components/rating-group/rating-group.svelte
new file mode 100644
index 000000000..8afd80c89
--- /dev/null
+++ b/src/uix/eidos/components/rating-group/rating-group.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {#snippet children(snippetProps)}
+ {@render children?.(snippetProps)}
+ {/snippet}
+
diff --git a/src/uix/eidos/components/rating-group/types.ts b/src/uix/eidos/components/rating-group/types.ts
new file mode 100644
index 000000000..ef699af34
--- /dev/null
+++ b/src/uix/eidos/components/rating-group/types.ts
@@ -0,0 +1,30 @@
+import type {
+ ItemProps as SomaRatingGroupItemProps,
+ ProviderProps as SomaRatingGroupProviderProps,
+ ProviderSnippetProps as RatingGroupProviderSnippetProps,
+ RatingItemDescriptor,
+ RatingItemState,
+ ItemSnippetProps as RatingGroupItemSnippetProps
+} from '$soma/components/rating-group';
+import type { ResponsiveProp, Size } from '$uix/eidos/lib/types';
+
+export type RatingGroupSize = Extract;
+
+/**
+ * Props for the eidos ``.
+ *
+ * Extends Soma's rating slider with visual sizing only. Value, hover preview,
+ * active/partial/inactive item state and ARIA are owned by Soma.
+ */
+export type RatingGroupProps = SomaRatingGroupProviderProps & {
+ /** Visual size. Accepts a responsive map resolved by ActiveEidos. @default 'md' */
+ size?: ResponsiveProp;
+};
+
+export type RatingGroupItemProps = SomaRatingGroupItemProps;
+export type {
+ RatingGroupProviderSnippetProps,
+ RatingGroupItemSnippetProps,
+ RatingItemDescriptor,
+ RatingItemState
+};
diff --git a/src/uix/eidos/generated/base.css b/src/uix/eidos/generated/base.css
index 2067ecf13..61dcfb8b2 100644
--- a/src/uix/eidos/generated/base.css
+++ b/src/uix/eidos/generated/base.css
@@ -735,6 +735,26 @@
--radio-group-label-font-weight: var(--font-weight-medium);
--radio-group-label-line-height: var(--leading-ui);
--radio-group-label-color: var(--color-content-primary);
+ --rating-group-gap-sm: var(--space-1);
+ --rating-group-gap-md: var(--space-1-5);
+ --rating-group-gap-lg: var(--space-2);
+ --rating-group-item-size-sm: 18px;
+ --rating-group-item-size-md: 22px;
+ --rating-group-item-size-lg: 28px;
+ --rating-group-font-family: var(--font-ui);
+ --rating-group-font-size-sm: var(--font-size-sm);
+ --rating-group-font-size-md: var(--font-size-md);
+ --rating-group-font-size-lg: var(--font-size-lg);
+ --rating-group-line-height: var(--leading-ui);
+ --rating-group-item-color-inactive: var(--color-neutral-border);
+ --rating-group-item-color-active: var(--color-fulfill-solid);
+ --rating-group-item-color-partial: var(--color-fulfill-solid);
+ --rating-group-item-hover-offset: -1px;
+ --rating-group-focus-radius: var(--radius-md);
+ --rating-group-focus-shadow: 0 0 0 var(--focus-ring-offset) var(--color-surface-default), 0 0 0 calc(var(--focus-ring-offset) + var(--focus-ring-width)) var(--focus-ring-color);
+ --rating-group-transition-duration: var(--duration-fast);
+ --rating-group-transition-ease: var(--ease-default);
+ --rating-group-disabled-opacity: 0.56;
--slider-track-size-sm: 4px;
--slider-track-size-md: 6px;
--slider-track-size-lg: 8px;
diff --git a/src/uix/eidos/index.css b/src/uix/eidos/index.css
index 6bdcfe5e1..34e2c0f8a 100644
--- a/src/uix/eidos/index.css
+++ b/src/uix/eidos/index.css
@@ -77,4 +77,5 @@
@import './components/tabs/tabs.css';
@import './components/checkbox/checkbox.css';
@import './components/radio-group/radio-group.css';
+@import './components/rating-group/rating-group.css';
@import './components/slider/slider.css';
diff --git a/src/uix/eidos/lib/recipes/base.ts b/src/uix/eidos/lib/recipes/base.ts
index 81df1c2c2..23ede292f 100644
--- a/src/uix/eidos/lib/recipes/base.ts
+++ b/src/uix/eidos/lib/recipes/base.ts
@@ -494,6 +494,29 @@ export const THEME_BASE_RECIPE_TOKENS = {
'label-line-height': 'var(--leading-ui)',
'label-color': 'var(--color-content-primary)'
},
+ 'rating-group': {
+ 'gap-sm': 'var(--space-1)',
+ 'gap-md': 'var(--space-1-5)',
+ 'gap-lg': 'var(--space-2)',
+ 'item-size-sm': '18px',
+ 'item-size-md': '22px',
+ 'item-size-lg': '28px',
+ 'font-family': 'var(--font-ui)',
+ 'font-size-sm': 'var(--font-size-sm)',
+ 'font-size-md': 'var(--font-size-md)',
+ 'font-size-lg': 'var(--font-size-lg)',
+ 'line-height': 'var(--leading-ui)',
+ 'item-color-inactive': 'var(--color-neutral-border)',
+ 'item-color-active': 'var(--color-fulfill-solid)',
+ 'item-color-partial': 'var(--color-fulfill-solid)',
+ 'item-hover-offset': '-1px',
+ 'focus-radius': 'var(--radius-md)',
+ 'focus-shadow':
+ '0 0 0 var(--focus-ring-offset) var(--color-surface-default), 0 0 0 calc(var(--focus-ring-offset) + var(--focus-ring-width)) var(--focus-ring-color)',
+ 'transition-duration': 'var(--duration-fast)',
+ 'transition-ease': 'var(--ease-default)',
+ 'disabled-opacity': '0.56'
+ },
slider: {
'track-size-sm': '4px',
'track-size-md': '6px',