Glass
Liquid Glass: the light-bending control-layer material, regular and clear.
SwiftUI: glassEffect(_:in:)
Regular glass
Adaptive — legible over anything.
Clear glass
For media-rich backgrounds.
Interactive tap me
Installation
npx shadcn@latest add https://cupertino-ui.baltoon.jp/r/glass.jsonRequires the theme tokens — see Installation if this is your first component.
Source
"use client";
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
/**
* Liquid Glass (iOS 26 / macOS Tahoe) — a floating, light-bending
* material for the CONTROL layer. Per Apple's guidance: use it for
* elements that float above content (bars, buttons, badges), never
* for the content itself, and avoid stacking glass on glass.
*
* `regular` adapts and stays legible anywhere; `clear` is more
* transparent and belongs over media-rich backgrounds.
*/
const glassVariants = cva("relative isolate", {
variants: {
variant: {
regular: "glass-regular",
clear: "glass-clear",
},
interactive: {
true: "cursor-default select-none transition-[transform,background-color] duration-200 ease-[cubic-bezier(0.34,1.56,0.64,1)] hover:bg-[color-mix(in_srgb,var(--glass-bg)_100%,rgba(255,255,255,0.12))] active:scale-[0.96] focus-visible:ring-[3px] focus-visible:ring-blue/40 outline-none",
false: "",
},
},
defaultVariants: {
variant: "regular",
interactive: false,
},
});
/** Moving specular sheen, the "liquid" part. Rendered on top. */
function GlassSheen() {
return (
<span
aria-hidden
data-slot="glass-sheen"
className="pointer-events-none absolute inset-0 -z-[1] overflow-hidden rounded-[inherit]"
>
<span className="absolute -inset-x-1/4 -top-3/4 h-full rotate-[-8deg] bg-[radial-gradient(50%_60%_at_50%_100%,rgba(255,255,255,0.28),transparent_70%)]" />
</span>
);
}
function Glass({
className,
variant,
interactive,
asChild: _ignored,
sheen = true,
children,
...props
}: React.ComponentProps<"div"> &
VariantProps<typeof glassVariants> & {
asChild?: never;
/** Disable the specular sheen layer. */
sheen?: boolean;
}) {
return (
<div
data-slot="glass"
className={cn(glassVariants({ variant, interactive }), className)}
{...props}
>
{sheen ? <GlassSheen /> : null}
{children}
</div>
);
}
export { Glass, GlassSheen, glassVariants };