# Material A surface component that provides visual depth and structure through different elevation and border styles. Supports both static and interactive variants, making it the foundational container for cards, panels, and interactive surfaces. ```tsx demo import { Material } from "@tenstorrent/vesper/material"; import { Typography } from "@tenstorrent/vesper/typography"; export default function MaterialDemo() { return ( This is a material surface. ); } ``` ## Options | Prop | Type | Description | Default | | ---------- | -------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | ------------ | | `variant` | `"outlined" \| "outlined-strong" \| "raised" \| "floating" \| "modal" \| "inset" \| "inset-strong" \| "interactive"` | The visual style variant of the material surface. | `"outlined"` | | `state` | `"disabled" \| "active" \| "selected"` | The current interaction state. Only applicable when `variant` is `"interactive"`. | — | | `as` | `ElementType` | The root element type for polymorphic rendering. | `"div"` | | `children` | `ReactNode` | The content rendered inside the material surface. | — | All other props are forwarded to the underlying `
` element, or whichever root element is specified via the `as` prop. A `Material` only provides the surface treatment (border, background, shadow, and radius); it does not apply any padding or layout of its own, so spacing is left up to you. ## Examples ### Basic usage Render a `Material` by giving it some children: ```tsx demo import { Material } from "@tenstorrent/vesper/material"; import { Typography } from "@tenstorrent/vesper/typography"; export default function BasicMaterial() { return ( Card content ); } ``` ### Variants A `Material` can be rendered in several different variants: | Variant | When to use | | ------------------- | -------------------------------------------------------------------------------------- | | `"outlined"` | Default variant. Use for surfaces that sit flat on the page, such as cards and panels. | | `"outlined-strong"` | Use when a surface needs a more defined boundary than the default outline provides. | | `"raised"` | Use for surfaces that should read as slightly lifted off the page. | | `"floating"` | Use for transient surfaces layered above page content, such as dropdowns and popovers. | | `"modal"` | Use for the topmost layer of the interface, such as dialogs and sheets. | | `"inset"` | Use for surfaces that should read as recessed into the page, such as code areas. | | `"inset-strong"` | Use when a recessed surface needs more depth than `"inset"` provides. | | `"interactive"` | Use for surfaces the user can act on, such as selectable cards. | ```tsx demo import { Material, MATERIAL_VARIANTS } from "@tenstorrent/vesper/material"; import { Typography } from "@tenstorrent/vesper/typography"; export default function MaterialVariants() { return (
{MATERIAL_VARIANTS.map((variant) => ( {variant} ))}
); } ``` ### Interactive surfaces Setting `variant="interactive"` adds hover and focus treatments to the surface. The `state` prop then describes the surface's current interaction state, and is only accepted by this variant: ```tsx demo import { Material } from "@tenstorrent/vesper/material"; import { Typography } from "@tenstorrent/vesper/typography"; export default function InteractiveMaterials() { return (
Default Active Selected Disabled
); } ``` ### Polymorphic usage You can use the `as` prop to specify what underlying element to render. Pair it with `variant="interactive"` when the surface itself is the control, so it is focusable and operable by keyboard: ```tsx demo import { useState } from "react"; import { Material } from "@tenstorrent/vesper/material"; import { Typography } from "@tenstorrent/vesper/typography"; export default function SelectableMaterials() { const [selected, setSelected] = useState("standard"); return (
{["standard", "priority"].map((value) => ( setSelected(value)} style={{ padding: "var(--vesper-spacing-4)", cursor: "pointer" }} > {value === "standard" ? "Standard shipping" : "Priority shipping"} ))}
); } ``` > [!NOTE] > > When `state="disabled"` is passed alongside an `as` prop that renders a natively disableable element (such as `button`), the underlying element is disabled for you. For any other element, `aria-disabled` is applied instead, along with `tabIndex={-1}` and handlers that suppress pointer, keyboard, and focus events.