Ir al contenido
uiify

Rating

Control para elegir una calificación en una fila de estrellas.

Navegadores
Chrome 123+Firefox 121+Safari 17.5+
Nivel
0
Tamaño comprimido
1.22 kB
Presupuesto de diseño forzado
0 ms
Presupuesto de axe
0
Compatible con SSR
Sí
Basado en
elements/choice
Contrato publicado
Entorno de pruebas

Zona de pruebas

Rating

Predeterminado

import { Rating } from "@gunkin/uiify";

export default function Example() {
  return <Rating className="" defaultValue={3} id="movie-rating" />;
}
/* Rating — a native radio group of stars. Inputs are visually hidden;
   flex-direction: row-reverse restores left-to-right visual order over
   reversed DOM order. Each input+label pair sits in its own [data-part="item"]
   wrapper (ChoiceGroup's shape), so `~` alone can't reach across pairs —
   `:has()` promotes a checked/hovered item onto its later (= more-preferred,
   thanks to row-reverse) sibling wrappers. This keeps the uncontrolled rating functional without
   JavaScript. */

@layer components {
  [data-uiify-rating] {
    display: inline-flex;
    flex-direction: row-reverse;
    gap: var(--space-xs);
  }

  [data-uiify-rating] > [data-part="item"] > input {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  [data-uiify-rating] > [data-part="item"] > label {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--input);
    font-size: 1.5rem;
    line-height: 1;
    cursor: pointer;
    transition: var(--transition-colors);
  }

  [data-uiify-rating] > [data-part="item"]:has(> input:checked) > label,
  [data-uiify-rating] > [data-part="item"]:has(> input:checked) ~ [data-part="item"] > label {
    color: var(--primary);
  }

  [data-uiify-rating]:not([data-disabled], [data-readonly])
    > [data-part="item"]:has(> label:hover)
    > label,
  [data-uiify-rating]:not([data-disabled], [data-readonly])
    > [data-part="item"]:has(> label:hover)
    ~ [data-part="item"]
    > label {
    color: var(--primary);
  }

  [data-uiify-rating] > [data-part="item"] > input:focus-visible ~ label {
    outline: none;
    box-shadow: 0 0 0 var(--ring-width) color-mix(in oklch, var(--ring) 16%, transparent);
    border-radius: var(--radius-xs);
    corner-shape: squircle;
  }

  [data-uiify-rating][data-readonly] > [data-part="item"] > label {
    cursor: default;
  }

  [data-uiify-rating][data-disabled] > [data-part="item"] > label {
    cursor: default;
    opacity: 0.5;
  }
}
import { Rating } from "@gunkin/uiify";

export default function Example() {
  return (
    <Rating
      className={
        "inline-flex [flex-direction:row-reverse] gap-xs [&>[data-part=item]>input]:absolute [&>[data-part=item]>inp" +
        "ut]:[inline-size:1px] [&>[data-part=item]>input]:[block-size:1px] [&>[data-part=item]>input]:[margin:-1px] " +
        "[&>[data-part=item]>input]:overflow-hidden [&>[data-part=item]>input]:[clip-path:inset(50%)] [&>[data-part=" +
        "item]>input]:whitespace-nowrap [&>[data-part=item]>label]:inline-flex [&>[data-part=item]>label]:items-cent" +
        "er [&>[data-part=item]>label]:justify-center [&>[data-part=item]>label]:text-input [&>[data-part=item]>labe" +
        "l]:[font-size:1.5rem] [&>[data-part=item]>label]:leading-none [&>[data-part=item]>label]:cursor-pointer [&>" +
        "[data-part=item]>label]:[transition:var(--transition-colors)] [&>[data-part=item]:has(>input:checked)>label" +
        "]:text-primary [&>[data-part=item]:has(>input:checked)~[data-part=item]>label]:text-primary [&:not([data-di" +
        "sabled],[data-readonly])>[data-part=item]:has(>label:hover)>label]:text-primary [&:not([data-disabled],[dat" +
        "a-readonly])>[data-part=item]:has(>label:hover)~[data-part=item]>label]:text-primary [&>[data-part=item]>in" +
        "put:focus-visible~label]:[outline:none] [&>[data-part=item]>input:focus-visible~label]:[box-shadow:0_0_0_va" +
        "r(--ring-width)_color-mix(in_oklch,_var(--ring)_16%,_transparent)] [&>[data-part=item]>input:focus-visible~" +
        "label]:rounded-xs [&>[data-part=item]>input:focus-visible~label]:[corner-shape:squircle] [&[data-readonly]>" +
        "[data-part=item]>label]:cursor-default [&[data-disabled]>[data-part=item]>label]:cursor-default [&[data-dis" +
        "abled]>[data-part=item]>label]:opacity-50"
      }
      defaultValue={3}
      id="movie-rating"
    />
  );
}
/* app.css */

@layer reset, ui, app, tokens, base, demo, components, utilities, theme;

@import "@gunkin/uiify/styles/reset";

@import "@gunkin/uiify/components/behavior.css";

@import "@gunkin/uiify/styles/tokens";

@import "@gunkin/uiify/styles/tailwind";

@import "tailwindcss/utilities.css";

@theme { --spacing: 0.25rem; --font-weight-normal: 400; --font-weight-medium: 500; --font-weight-semibold: 600; --font-weight-bold: 700; }

@source inline('inline-flex [flex-direction:row-reverse] gap-xs [&>[data-part=item]>input]:absolute [&>[data-part=item]>input]:[inline-size:1px] [&>[data-part=item]>input]:[block-size:1px] [&>[data-part=item]>input]:[margin:-1px] [&>[data-part=item]>input]:overflow-hidden [&>[data-part=item]>input]:[clip-path:inset(50%)] [&>[data-part=item]>input]:whitespace-nowrap [&>[data-part=item]>label]:inline-flex [&>[data-part=item]>label]:items-center [&>[data-part=item]>label]:justify-center [&>[data-part=item]>label]:text-input [&>[data-part=item]>label]:[font-size:1.5rem] [&>[data-part=item]>label]:leading-none [&>[data-part=item]>label]:cursor-pointer [&>[data-part=item]>label]:[transition:var(--transition-colors)] [&>[data-part=item]:has(>input:checked)>label]:text-primary [&>[data-part=item]:has(>input:checked)~[data-part=item]>label]:text-primary [&:not([data-disabled],[data-readonly])>[data-part=item]:has(>label:hover)>label]:text-primary [&:not([data-disabled],[data-readonly])>[data-part=item]:has(>label:hover)~[data-part=item]>label]:text-primary [&>[data-part=item]>input:focus-visible~label]:[outline:none] [&>[data-part=item]>input:focus-visible~label]:[box-shadow:0_0_0_var(--ring-width)_color-mix(in_oklch,_var(--ring)_16%,_transparent)] [&>[data-part=item]>input:focus-visible~label]:rounded-xs [&>[data-part=item]>input:focus-visible~label]:[corner-shape:squircle] [&[data-readonly]>[data-part=item]>label]:cursor-default [&[data-disabled]>[data-part=item]>label]:cursor-default [&[data-disabled]>[data-part=item]>label]:opacity-50');

@layer base { :root { --uiify-control-text: var(--text-sm); } @media (pointer: coarse) { :root { --uiify-control-text: var(--text-base); } } }

/* Authored animation and registered properties used by the Tailwind skin.
 * Visual rules belong in utility recipes; only at-rule definitions live here. */
@layer components {
  @keyframes uiify-presence-in {
    from {
      opacity: 0;
      scale: var(--presence-scale);
    }
  }
}

@layer components {
  @keyframes uiify-presence-out {
    to {
      opacity: 0;
      scale: var(--presence-scale);
    }
  }
}

@property --uiify-spinner-tail {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

@property --uiify-spinner-length {
  syntax: "<angle>";
  inherits: false;
  initial-value: 36deg;
}

@layer components {
  @keyframes uiify-spinner-rotate {
    to {
      transform: rotate(360deg);
    }
  }
}

@layer components {
  @keyframes uiify-spinner-orbit {
    0% {
      --uiify-spinner-tail: 0deg;
      --uiify-spinner-length: 36deg;
    }

    50% {
      --uiify-spinner-tail: 90deg;
      --uiify-spinner-length: 324deg;
    }

    100% {
      --uiify-spinner-tail: 360deg;
      --uiify-spinner-length: 36deg;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-pulse {
    50% {
      opacity: 0.45;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-shimmer {
    to {
      background-position: -200% 0;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-reveal {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }
}

@property --candle-body-height {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-body-top {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --candle-slot {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 100%;
}

@property --candle-wick-height {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-wick-top {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --candle-x {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-scale {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

@property --line-y {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --line-prev-y {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --line-count {
  syntax: "<integer>";
  inherits: false;
  initial-value: 1;
}

@property --line-scale {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

@layer components {
  @keyframes uiify-otp-input-caret-blink {
    50% {
      opacity: 0;
    }
  }
}

API

Rating

PropTipoPredeterminadoDescripción
id*string—Prefijo de id para el grupo y para cada input de botón de opción generado.
defaultValuenumber0Calificación seleccionada en el primer renderizado; la selección y la vista previa al pasar el puntero usan botones de opción nativos y CSS, por lo que funcionan sin JavaScript.
maxnumber5Número de elementos de calificación renderizados.
readOnlybooleanfalseMuestra la calificación sin permitir que el usuario la cambie.
disabledbooleanfalseDesactiva todos los botones de opción de la calificación.
classNamestring—Clase aplicada al elemento de calificación.
aria-labelstring—Nombre accesible del grupo de calificación.

Teclado

TeclaAcción
TabLlevar el foco al control o sacarlo de él
Enter / SpaceActivar cuando tiene el foco (controles de tipo botón)

Accesibilidad

Usa HTML semántico siempre que es posible. Inspecciona el marcado renderizado en el entorno de pruebas: ARIA se añade solo cuando los elementos nativos no bastan.

Puntos de estilo

data-disabled
Esta página se tradujo automáticamente y aún no se ha revisado.