Surface
Groups related content on an opaque paper or translucent glass layer.
Storage
Workspace usage this month
18.4 GB
of 50 GB used
Playground
materialSets an opaque paper or translucent glass surface.
interactiveMakes this example render the surface as a focusable button.
Usage
import { Surface } from "earthling-ui/surface";
export function Example() {
return (
<>
<Surface material="paper">
<h3>Storage</h3>
<p>18.4 GB of 50 GB used.</p>
</Surface>
</>
);
}
- Use paper for dependable contrast and glass only where the background supports translucency.
- When interactive is true, render Surface as a semantic button or link with asChild.
- Avoid nesting equal corner radii; reduce the inner radius by the surrounding inset.
Installation
Start with the project setup for React and Tailwind CSS 4. Both paths use the same component and theme.
npm install earthling-uiUse the component import shown above. Package updates keep the implementation current.
API reference
Declarations from the current library build, including inherited primitive props. Playground controls above show selected options; they are not the complete API.
// Generated by dts-bundle-generator v9.5.1
import { VariantProps } from 'class-variance-authority';
import { ComponentProps } from 'react';
declare const surfaceVariants: (props?: ({
material?: "paper" | "glass" | null | undefined;
interactive?: boolean | null | undefined;
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
export interface SurfaceProps extends ComponentProps<"div">, VariantProps<typeof surfaceVariants> {
asChild?: boolean;
}
export declare const Surface: import("react").ForwardRefExoticComponent<Omit<SurfaceProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
export {};Runtime dependencies: @radix-ui/react-slot, class-variance-authority, cnfast.
Source
Use the eject command to copy this implementation with its required helpers and project-specific imports.
View Surface implementation
"use client";
import { cn } from "@/utils/cn";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
import { type ComponentProps, forwardRef } from "react";
const surfaceVariants = cva(
"relative flow-root rounded-lg border p-4 text-foreground",
{
variants: {
material: {
paper: "border-current/10 bg-surface shadow-xs",
glass:
"border-current/10 bg-surface/75 shadow-xs backdrop-blur-sm before:pointer-events-none before:absolute before:inset-[-1px] before:rounded-[inherit] before:bg-[linear-gradient(var(--color-light),transparent_45%)] before:p-px before:[mask-clip:content-box,_border-box] before:[mask-composite:exclude] before:[mask-image:linear-gradient(#000,#000),_linear-gradient(#000,#000)] before:[mask-origin:content-box,_border-box] before:select-none",
},
interactive: {
true: "cursor-pointer hover:border-current/20 hover:bg-current/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-outline",
false: "",
},
},
compoundVariants: [
{
material: "glass",
interactive: true,
className: "hover:border-current/20 hover:bg-surface/90",
},
],
defaultVariants: {
interactive: false,
material: "glass",
},
},
);
export interface SurfaceProps
extends ComponentProps<"div">, VariantProps<typeof surfaceVariants> {
asChild?: boolean;
}
const Surface = forwardRef<HTMLDivElement, SurfaceProps>(
({ className, asChild, interactive, material, ...props }, ref) => {
const Comp = asChild ? Slot : "div";
return (
<Comp
className={cn(surfaceVariants({ interactive, material }), className)}
ref={ref}
{...props}
/>
);
},
);
Surface.displayName = "Surface";
export { Surface };