"use client";
import { useEffect, useRef, useState } from "react";
import {
LikeBurst,
type LikeBurstHandle,
} from "@/components/interior/like-burst";
export function LikeBurstDemo() {
const ref = useRef<LikeBurstHandle>(null);
const [liked, setLiked] = useState(false);
useEffect(() => {
if (!liked) return;
const back = setTimeout(() => ref.current?.toggle(), 1500);
return () => clearTimeout(back);
}, [liked]);
return (
<div className="flex justify-center">
<LikeBurst ref={ref} initialCount={128} onToggle={setLiked} />
</div>
);
}
Like Burst Demo
By Özer
Try the interaction, copy the React source files, or download the complete example.
About Like Burst Demo
Like Burst Demo is an animated React and Tailwind CSS button by Özer. Try the interaction, copy the React source, or download the example with creator credit.
- Effects and categories
- Hover effects, Animated
- Using this example
- Copy a TSX file or download the original source and standalone demo. Test keyboard focus, motion and contrast in your own project.
Usage, Tailwind and licensing questions
Read the source files
lib/demos/like-burst-demo.tsx
"use client";
import { useEffect, useRef, useState } from "react";
import {
LikeBurst,
type LikeBurstHandle,
} from "@/components/interior/like-burst";
export function LikeBurstDemo() {
const ref = useRef<LikeBurstHandle>(null);
const [liked, setLiked] = useState(false);
useEffect(() => {
if (!liked) return;
const back = setTimeout(() => ref.current?.toggle(), 1500);
return () => clearTimeout(back);
}, [liked]);
return (
<div className="flex justify-center">
<LikeBurst ref={ref} initialCount={128} onToggle={setLiked} />
</div>
);
}
components/interior/like-burst.tsx
"use client";
import {
useCallback,
useEffect,
useImperativeHandle,
useRef,
useState,
} from "react";
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
const EASE = [0.23, 1, 0.32, 1] as const;
const CELL = { type: "spring", stiffness: 520, damping: 34, mass: 0.45 } as const;
const CROSSFADE = { type: "spring", stiffness: 260, damping: 34, mass: 0.8 } as const;
const INSTANT = { duration: 0 } as const;
const HEART =
"M12 20.3 4.3 12.6a4.8 4.8 0 0 1 6.8-6.8l.9.9.9-.9a4.8 4.8 0 0 1 6.8 6.8Z";
const SPARKS = Array.from({ length: 8 }, (_, i) => {
const h = (((i + 1) * 2654435761) % 997) / 997;
const angle = (i / 8) * Math.PI * 2 - Math.PI / 2 + (h - 0.5) * 0.4;
const distance = 13 + h * 9;
return {
x: Math.round(Math.cos(angle) * distance * 10) / 10,
y: Math.round(Math.sin(angle) * distance * 10) / 10,
size: h > 0.5 ? 4 : 3,
delay: Math.round(h * 50) / 1000,
};
});
const DEFAULT_FORMAT = (value: number) =>
new Intl.NumberFormat("en-US").format(value);
export type LikeCommit = (
liked: boolean,
signal: AbortSignal,
) => Promise<unknown>;
export type LikeBurstHandle = {
toggle: () => void;
};
export type UseOptimisticLikeOptions = {
initialLiked?: boolean;
initialCount?: number;
onCommit?: LikeCommit;
onError?: (error: unknown) => void;
settle?: number;
};
export type OptimisticLike = {
liked: boolean;
count: number;
base: number;
pending: boolean;
burst: number;
settled: { liked: boolean; count: number };
toggle: () => void;
};
export function useOptimisticLike({
initialLiked = false,
initialCount = 0,
onCommit,
onError,
settle = 400,
}: UseOptimisticLikeOptions = {}): OptimisticLike {
const [liked, setLiked] = useState(initialLiked);
const [count, setCount] = useState(initialCount);
const [pending, setPending] = useState(false);
const [burst, setBurst] = useState(0);
const [settled, setSettled] = useState({
liked: initialLiked,
count: initialCount,
});
const likedNow = useRef(initialLiked);
const countNow = useRef(initialCount);
const truth = useRef({ liked: initialLiked, count: initialCount });
const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
const inFlight = useRef<AbortController | null>(null);
const seq = useRef(0);
const commit = useRef(onCommit);
commit.current = onCommit;
const failed = useRef(onError);
failed.current = onError;
const flush = useCallback(() => {
timer.current = null;
inFlight.current?.abort();
inFlight.current = null;
seq.current += 1;
const intent = likedNow.current;
if (intent === truth.current.liked) {
countNow.current = truth.current.count;
setLiked(truth.current.liked);
setCount(truth.current.count);
setPending(false);
return;
}
const target = { liked: intent, count: countNow.current };
const run = commit.current;
if (!run) {
truth.current = target;
setSettled(target);
setPending(false);
return;
}
const controller = new AbortController();
const id = seq.current;
inFlight.current = controller;
setPending(true);
run(intent, controller.signal).then(
() => {
if (id !== seq.current) return;
inFlight.current = null;
truth.current = target;
setSettled(target);
setPending(false);
},
(error: unknown) => {
if (id !== seq.current) return;
inFlight.current = null;
likedNow.current = truth.current.liked;
countNow.current = truth.current.count;
setLiked(truth.current.liked);
setCount(truth.current.count);
setPending(false);
failed.current?.(error);
},
);
}, []);
const toggle = useCallback(() => {
const next = !likedNow.current;
likedNow.current = next;
countNow.current += next ? 1 : -1;
setLiked(next);
setCount(countNow.current);
setPending(true);
if (next) setBurst((b) => b + 1);
if (timer.current) clearTimeout(timer.current);
timer.current = setTimeout(flush, settle);
}, [flush, settle]);
useEffect(
() => () => {
if (timer.current) clearTimeout(timer.current);
timer.current = null;
seq.current += 1;
inFlight.current?.abort();
inFlight.current = null;
},
[],
);
return {
liked,
count,
base: liked ? count - 1 : count,
pending,
burst,
settled,
toggle,
};
}
export type LikeBurstProps = {
initialLiked?: boolean;
initialCount?: number;
onCommit?: LikeCommit;
onError?: (error: unknown) => void;
onToggle?: (liked: boolean) => void;
settle?: number;
label?: string;
activeLabel?: string;
format?: (value: number) => string;
disabled?: boolean;
className?: string;
};
export function LikeBurst({
initialLiked = false,
initialCount = 0,
onCommit,
onError,
onToggle,
settle = 400,
label = "Like",
activeLabel = "Liked",
format = DEFAULT_FORMAT,
disabled = false,
className = "",
ref,
}: LikeBurstProps & { ref?: React.Ref<LikeBurstHandle> }) {
const reduced = useReducedMotion();
const { liked, count, base, pending, burst, settled, toggle } =
useOptimisticLike({ initialLiked, initialCount, onCommit, onError, settle });
useImperativeHandle(ref, () => ({ toggle }), [toggle]);
const low = format(base);
const high = format(base + 1);
const widest = high.length >= low.length ? high : low;
const shown = format(count);
return (
<span className={`inline-flex items-center ${className}`}>
<button
type="button"
disabled={disabled}
aria-pressed={liked}
aria-busy={pending}
aria-label={label}
onClick={() => {
toggle();
onToggle?.(!liked);
}}
style={{ touchAction: "manipulation" }}
className="inline-flex h-9 select-none items-center gap-2 rounded-[9px] border border-stone-200 bg-white px-3 text-[13px] font-medium text-stone-700 outline-none focus-visible:ring-2 focus-visible:ring-stone-400 disabled:opacity-50 dark:border-white/[0.16] dark:bg-[#1D1D1A] dark:text-stone-200 dark:focus-visible:ring-stone-500"
>
<span aria-hidden className="relative block size-[18px]">
<motion.svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth={1.7}
strokeLinejoin="round"
className="absolute inset-0 size-[18px] text-stone-500 dark:text-stone-400"
initial={false}
animate={{ opacity: liked ? 0 : 1 }}
transition={reduced ? INSTANT : CROSSFADE}
>
<path d={HEART} />
</motion.svg>
<motion.svg
viewBox="0 0 24 24"
fill="currentColor"
className="absolute inset-0 size-[18px] text-stone-800 dark:text-stone-100"
initial={false}
animate={{ opacity: liked ? 1 : 0, scale: liked ? 1 : 0.55 }}
transition={reduced ? INSTANT : CELL}
>
<path d={HEART} />
</motion.svg>
{!reduced && burst > 0 ? (
<span
key={burst}
className="pointer-events-none absolute left-1/2 top-1/2 block size-0"
>
{SPARKS.map((spark, i) => (
<motion.span
key={i}
className="absolute block rounded-[1.5px] bg-stone-800 dark:bg-stone-100"
style={{
width: spark.size,
height: spark.size,
marginLeft: -spark.size / 2,
marginTop: -spark.size / 2,
}}
initial={{ x: 0, y: 0, scale: 0.6, opacity: 0.85 }}
animate={{ x: spark.x, y: spark.y, scale: 1, opacity: 0 }}
transition={{ duration: 0.44, delay: spark.delay, ease: EASE }}
/>
))}
</span>
) : null}
</span>
<span aria-hidden className="grid">
<motion.span
className="col-start-1 row-start-1"
initial={false}
animate={{ opacity: liked ? 0 : 1 }}
transition={reduced ? INSTANT : CROSSFADE}
>
{label}
</motion.span>
<motion.span
className="col-start-1 row-start-1"
initial={false}
animate={{ opacity: liked ? 1 : 0 }}
transition={reduced ? INSTANT : CROSSFADE}
>
{activeLabel}
</motion.span>
</span>
<span
aria-hidden
className="grid overflow-hidden text-[12px] tabular-nums text-stone-500 dark:text-stone-400"
>
<span className="invisible col-start-1 row-start-1">{widest}</span>
<AnimatePresence initial={false}>
<motion.span
key={shown}
className="col-start-1 row-start-1 justify-self-end"
initial={{ opacity: 0, y: reduced ? 0 : -7 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: reduced ? 0 : 7 }}
transition={reduced ? INSTANT : CROSSFADE}
>
{shown}
</motion.span>
</AnimatePresence>
</span>
</button>
<span role="status" aria-live="polite" className="sr-only">
{`${format(settled.count)} likes, ${settled.liked ? "liked" : "not liked"}`}
</span>
</span>
);
}
demo.tsx
export { LikeBurstDemo as default } from "@/lib/demos/like-burst-demo";CSS
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
@layer properties;
@layer theme, base, components, utilities;
@layer theme {
:root, :host {
--color-stone-100: oklch(97% 0.001 106.424);
--color-stone-200: oklch(92.3% 0.003 48.717);
--color-stone-400: oklch(70.9% 0.01 56.259);
--color-stone-500: oklch(55.3% 0.013 58.071);
--color-stone-700: oklch(37.4% 0.01 67.558);
--color-stone-800: oklch(26.8% 0.007 34.298);
--color-white: #fff;
--spacing: 0.25rem;
--font-weight-medium: 500;
--default-transition-duration: 150ms;
--default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
--default-font-family: var(--font-geist-sans);
--default-mono-font-family: var(--font-geist-mono);
}
}
@layer base {
*, ::after, ::before, ::backdrop, ::file-selector-button {
box-sizing: border-box;
margin: 0;
padding: 0;
border: 0 solid;
}
html, :host {
line-height: 1.5;
-webkit-text-size-adjust: 100%;
tab-size: 4;
font-family: var(--default-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");
font-feature-settings: var(--default-font-feature-settings, normal);
font-variation-settings: var(--default-font-variation-settings, normal);
-webkit-tap-highlight-color: transparent;
}
hr {
height: 0;
color: inherit;
border-top-width: 1px;
}
abbr:where([title]) {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
}
h1, h2, h3, h4, h5, h6 {
font-size: inherit;
font-weight: inherit;
}
a {
color: inherit;
-webkit-text-decoration: inherit;
text-decoration: inherit;
}
b, strong {
font-weight: bolder;
}
code, kbd, samp, pre {
font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);
font-feature-settings: var(--default-mono-font-feature-settings, normal);
font-variation-settings: var(--default-mono-font-variation-settings, normal);
font-size: 1em;
}
small {
font-size: 80%;
}
sub, sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
table {
text-indent: 0;
border-color: inherit;
border-collapse: collapse;
}
:-moz-focusring:where(:not(iframe)) {
outline: auto;
}
progress {
vertical-align: baseline;
}
summary {
display: list-item;
}
ol, ul, menu {
list-style: none;
}
img, svg, video, canvas, audio, iframe, embed, object {
display: block;
vertical-align: middle;
}
img, video {
max-width: 100%;
height: auto;
}
button, input, select, optgroup, textarea, ::file-selector-button {
font: inherit;
font-feature-settings: inherit;
font-variation-settings: inherit;
letter-spacing: inherit;
color: inherit;
border-radius: 0;
background-color: transparent;
opacity: 1;
}
:where(select:is([multiple], [size])) optgroup {
font-weight: bolder;
}
:where(select:is([multiple], [size])) optgroup option {
padding-inline-start: 20px;
}
::file-selector-button {
margin-inline-end: 4px;
}
::placeholder {
opacity: 1;
}
@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {
::placeholder {
color: currentcolor;
@supports (color: color-mix(in lab, red, red)) {
color: color-mix(in oklab, currentcolor 50%, transparent);
}
}
}
textarea {
resize: vertical;
}
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-date-and-time-value {
min-height: 1lh;
text-align: inherit;
}
::-webkit-datetime-edit {
display: inline-flex;
}
::-webkit-datetime-edit-fields-wrapper {
padding: 0;
}
::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {
padding-block: 0;
}
::-webkit-calendar-picker-indicator {
line-height: 1;
}
:-moz-ui-invalid {
box-shadow: none;
}
button, input:where([type="button"], [type="reset"], [type="submit"]), ::file-selector-button {
appearance: button;
}
::-webkit-inner-spin-button, ::-webkit-outer-spin-button {
height: auto;
}
[hidden]:where(:not([hidden="until-found"])) {
display: none !important;
}
}
@layer utilities {
.pointer-events-none {
pointer-events: none;
}
.invisible {
visibility: hidden;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border-width: 0;
}
.absolute {
position: absolute;
}
.relative {
position: relative;
}
.inset-0 {
inset: 0px;
}
.top-1\/2 {
top: calc(1 / 2 * 100%);
}
.left-1\/2 {
left: calc(1 / 2 * 100%);
}
.col-start-1 {
grid-column-start: 1;
}
.row-start-1 {
grid-row-start: 1;
}
.block {
display: block;
}
.flex {
display: flex;
}
.grid {
display: grid;
}
.inline-flex {
display: inline-flex;
}
.size-0 {
width: 0px;
height: 0px;
}
.size-\[18px\] {
width: 18px;
height: 18px;
}
.h-9 {
height: calc(var(--spacing) * 9);
}
.items-center {
align-items: center;
}
.justify-center {
justify-content: center;
}
.gap-2 {
gap: calc(var(--spacing) * 2);
}
.justify-self-end {
justify-self: flex-end;
}
.overflow-hidden {
overflow: hidden;
}
.rounded-\[1\.5px\] {
border-radius: 1.5px;
}
.rounded-\[9px\] {
border-radius: 9px;
}
.border {
border-style: var(--tw-border-style);
border-width: 1px;
}
.border-stone-200 {
border-color: var(--color-stone-200);
}
.bg-stone-800 {
background-color: var(--color-stone-800);
}
.bg-white {
background-color: var(--color-white);
}
.px-3 {
padding-inline: calc(var(--spacing) * 3);
}
.text-\[12px\] {
font-size: 12px;
}
.text-\[13px\] {
font-size: 13px;
}
.font-medium {
--tw-font-weight: var(--font-weight-medium);
font-weight: var(--font-weight-medium);
}
.text-stone-500 {
color: var(--color-stone-500);
}
.text-stone-700 {
color: var(--color-stone-700);
}
.text-stone-800 {
color: var(--color-stone-800);
}
.tabular-nums {
--tw-numeric-spacing: tabular-nums;
font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);
}
.transition {
transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events;
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
transition-duration: var(--tw-duration, var(--default-transition-duration));
}
.outline-none {
--tw-outline-style: none;
outline-style: none;
}
.select-none {
-webkit-user-select: none;
user-select: none;
}
.focus-visible\:ring-2:focus-visible {
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
}
.focus-visible\:ring-stone-400:focus-visible {
--tw-ring-color: var(--color-stone-400);
}
.disabled\:opacity-50:disabled {
opacity: 50%;
}
.dark\:border-white\/\[0\.16\]:where(.dark, .dark *) {
border-color: color-mix(in srgb, #fff 16%, transparent);
@supports (color: color-mix(in lab, red, red)) {
border-color: color-mix(in oklab, var(--color-white) 16%, transparent);
}
}
.dark\:bg-\[\#1D1D1A\]:where(.dark, .dark *) {
background-color: #1D1D1A;
}
.dark\:bg-stone-100:where(.dark, .dark *) {
background-color: var(--color-stone-100);
}
.dark\:text-stone-100:where(.dark, .dark *) {
color: var(--color-stone-100);
}
.dark\:text-stone-200:where(.dark, .dark *) {
color: var(--color-stone-200);
}
.dark\:text-stone-400:where(.dark, .dark *) {
color: var(--color-stone-400);
}
.dark\:focus-visible\:ring-stone-500:where(.dark, .dark *):focus-visible {
--tw-ring-color: var(--color-stone-500);
}
}
:root {
--background: #fff;
--foreground: #111;
--primary: #171717;
--primary-foreground: #fff;
--secondary: #eee;
--secondary-foreground: #171717;
--muted: #eee;
--muted-foreground: #666;
--accent: #eee;
--accent-foreground: #171717;
--border: #ddd;
--input: #ddd;
--ring: #777;
--destructive: #dc2626;
--destructive-foreground: #fff;
--popover: #fff;
--popover-foreground: #111;
--success: #15803d;
--success-foreground: #fff;
--radius: .625rem;
--hairline: 1px;
}
.dark {
--background: #090909;
--foreground: #fafafa;
--primary: #fafafa;
--primary-foreground: #171717;
--secondary: #262626;
--secondary-foreground: #fafafa;
--muted: #262626;
--muted-foreground: #a3a3a3;
--accent: #262626;
--accent-foreground: #fafafa;
--border: #333;
--input: #333;
--popover: #171717;
--popover-foreground: #fafafa;
}
:root {
--bezel: #ffffff;
--panel: #ffffff;
--well: #ffffff;
--sub: #fafafa;
--hairline: rgba(0, 0, 0, 0.14);
--hairline-strong: rgba(0, 0, 0, 0.26);
--ink: #131313;
--ink-2: #454545;
--ink-3: #6e6e6e;
--accent: #4568ff;
--accent-soft: #edf1ff;
--moss: #3d7a4e;
--flag: #c0442f;
--shadow-float: 0 28px 56px -24px rgba(0, 0, 0, 0.22),
0 0 0 1px rgba(0, 0, 0, 0.06);
--shadow-lift: 0 1px 2px rgba(0, 0, 0, 0.04),
0 0 0 1px rgba(0, 0, 0, 0.11);
--shadow-well: inset 0 1px 2px rgba(0, 0, 0, 0.05),
inset 0 0 0 1px rgba(0, 0, 0, 0.1);
--shadow-cap: 0 1.5px 0 rgba(0, 0, 0, 0.09),
inset 0 0 0 1px rgba(0, 0, 0, 0.11);
--shadow-row: inset 0 0 0 1px rgba(0, 0, 0, 0.07),
0 1px 2px rgba(0, 0, 0, 0.05);
}
.dark {
--bezel: #141312;
--panel: #1d1d1a;
--well: #252522;
--sub: #1a1a17;
--hairline: rgba(255, 255, 255, 0.16);
--hairline-strong: rgba(255, 255, 255, 0.28);
--ink: #f8f8f4;
--ink-2: #c2c2ba;
--ink-3: #93938b;
--accent: #93b0ff;
--accent-soft: rgba(147, 176, 255, 0.14);
--moss: #5bd79c;
--flag: #f5897f;
--shadow-float: 0 28px 56px -22px rgba(0, 0, 0, 0.7),
0 0 0 1px rgba(255, 255, 255, 0.05);
--shadow-lift: 0 1px 2px rgba(0, 0, 0, 0.4),
inset 0 1px 0 rgba(255, 255, 255, 0.05),
0 0 0 1px rgba(255, 255, 255, 0.05);
--shadow-well: inset 0 1px 3px rgba(0, 0, 0, 0.4),
inset 0 0 0 1px rgba(255, 255, 255, 0.03);
--shadow-cap: 0 1.5px 0 rgba(0, 0, 0, 0.5),
inset 0 0 0 1px rgba(255, 255, 255, 0.1);
--shadow-row: inset 0 0 0 1px rgba(255, 255, 255, 0.06),
0 1px 2px rgba(0, 0, 0, 0.25);
}
@keyframes reaction-drift {
to {
transform: translateX(-50%);
}
}
@property --tw-border-style {
syntax: "*";
inherits: false;
initial-value: solid;
}
@property --tw-font-weight {
syntax: "*";
inherits: false;
}
@property --tw-ordinal {
syntax: "*";
inherits: false;
}
@property --tw-slashed-zero {
syntax: "*";
inherits: false;
}
@property --tw-numeric-figure {
syntax: "*";
inherits: false;
}
@property --tw-numeric-spacing {
syntax: "*";
inherits: false;
}
@property --tw-numeric-fraction {
syntax: "*";
inherits: false;
}
@property --tw-shadow {
syntax: "*";
inherits: false;
initial-value: 0 0 #0000;
}
@property --tw-shadow-color {
syntax: "*";
inherits: false;
}
@property --tw-shadow-alpha {
syntax: "<percentage>";
inherits: false;
initial-value: 100%;
}
@property --tw-inset-shadow {
syntax: "*";
inherits: false;
initial-value: 0 0 #0000;
}
@property --tw-inset-shadow-color {
syntax: "*";
inherits: false;
}
@property --tw-inset-shadow-alpha {
syntax: "<percentage>";
inherits: false;
initial-value: 100%;
}
@property --tw-ring-color {
syntax: "*";
inherits: false;
}
@property --tw-ring-shadow {
syntax: "*";
inherits: false;
initial-value: 0 0 #0000;
}
@property --tw-inset-ring-color {
syntax: "*";
inherits: false;
}
@property --tw-inset-ring-shadow {
syntax: "*";
inherits: false;
initial-value: 0 0 #0000;
}
@property --tw-ring-inset {
syntax: "*";
inherits: false;
}
@property --tw-ring-offset-width {
syntax: "<length>";
inherits: false;
initial-value: 0px;
}
@property --tw-ring-offset-color {
syntax: "*";
inherits: false;
initial-value: #fff;
}
@property --tw-ring-offset-shadow {
syntax: "*";
inherits: false;
initial-value: 0 0 #0000;
}
@layer properties {
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
*, ::before, ::after, ::backdrop {
--tw-border-style: solid;
--tw-font-weight: initial;
--tw-ordinal: initial;
--tw-slashed-zero: initial;
--tw-numeric-figure: initial;
--tw-numeric-spacing: initial;
--tw-numeric-fraction: initial;
--tw-shadow: 0 0 #0000;
--tw-shadow-color: initial;
--tw-shadow-alpha: 100%;
--tw-inset-shadow: 0 0 #0000;
--tw-inset-shadow-color: initial;
--tw-inset-shadow-alpha: 100%;
--tw-ring-color: initial;
--tw-ring-shadow: 0 0 #0000;
--tw-inset-ring-color: initial;
--tw-inset-ring-shadow: 0 0 #0000;
--tw-ring-inset: initial;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-offset-shadow: 0 0 #0000;
}
}
}