Surface

Updated:

An unopinionated visual primitive. A plain block by default that gains visual treatment via attributes.

Properties

Learn more about properties.

background

Applies a background color from the design-system token palette. When unset, the surface is transparent.

backgroundGradient
background-gradient

Applies a gradient fade across the background.

Direction and colors are customizable via CSS custom properties.

border

Renders a visible border around the surface, optionally in a themed color.

borderGradient
border-gradient

Renders the border as a gradient using the color set by the border prop. Takes precedence over a solid border when both are set.

Requires border to be set to produce a colored gradient. Without border, falls back to the default border color.

clickable

Makes the surface interactive, responding to clicks.

Emits tctClick when clicked.

elevation

Gives the component a drop shadow.

0 means no shadow; higher values appear more elevated.

inset

Adds internal padding applied uniformly on all sides.

Individual axes can be overridden with inset-x and inset-y.

insetX
inset-x

Adds horizontal padding, overriding the horizontal component of inset.

insetY
inset-y

Adds vertical padding, overriding the vertical component of inset.

radius

Adds corner rounding on a scale from 0 (sharp) to 5 (most rounded).

Events

The q2-surface element exposes events that can be used to send and receive data from the component based on user interaction.

Learn more about events.

tctClick

Emitted when the surface is clicked and clickable is true.

Event Detail Type signature

void

Methods

The q2-surface element exposes methods that can be used to perform various actions on the component.

Learn more about methods.

animate

Triggers a named animation on the surface. If an animation is already running, cancels it before starting the new one.

Type signature

animate(animation?: "bounce" | "flash" | "pulse" | "tada") => Promise<void>

Development

Transparent by default

q2-surface renders no visual treatment unless you apply props. A bare element with no props renders as an invisible block that takes up flow space but shows no background, border, or shadow.

Useful as a layout wrapper or padding shim

<q2-surface>
    <p>Useful as a layout wrapper or padding shim</p>
</q2-surface>

Add background="primary" to give it the theme's primary color.

Primary surface background color

<q2-surface background="primary">
    <p>Primary surface background color</p>
</q2-surface>

Inset

inset-x and inset-y only set the padding on their respective axis, taking priority over inset. Setting an axis to none removes padding on that axis even when inset is set to a larger value. This lets you mix uniform padding with full-bleed content on one axis.

Setting inset alone applies the same padding to both axes.

Horizontal padding only

<q2-surface border="default" inset="comfortable" background="default">
    <p>Horizontal padding only</p>
</q2-surface>

Setting inset-x and inset-y controls each axis independently.

Compact vertical, comfortable horizontal

<q2-surface border="default" inset-x="comfortable" inset-y="none" background="default">
    <p>Compact vertical, comfortable horizontal</p>
</q2-surface>

Border gradient requires a border color

border-gradient reads its gradient colors from the border prop. Without border, it falls back to the default border color. When both border and border-gradient are set, the gradient is applied to the border.

Colored gradient border

<q2-surface border="primary" border-gradient inset="normal" radius="2">
    <p>Colored gradient border</p>
</q2-surface>

Combining background and border gradients

background-gradient and border-gradient are independent props and work together. Use both for a glowing-card treatment where the border fades through the border color and the fill fades through the background color.

Content

<q2-surface
    border-gradient
    border="default"
    radius="2"
    inset="normal"
>
    <p>Content</p>
</q2-surface>

Clickable surfaces

clickable adds role="button" and tabIndex=0 automatically. Keyboard users can Tab to focus and activate with Enter or Space at no extra cost. The component emits tctClick on activation which should be listened for instead of a native click event, so your handler catches both pointer and keyboard activations.

Click or press Enter to activate

<q2-surface id="my-surface" clickable radius="2" elevation="2" border="default" inset="normal" background="default">
    <p>Click or press Enter to activate</p>
</q2-surface>
document.getElementById('my-surface').addEventListener('tctClick', () => {
    console.log('surface activated');
});

animate() method

animate() accepts 'bounce', 'flash', 'pulse', or 'tada' and defaults to 'pulse'. It returns a Promise that resolves when the animation ends, enabling sequential choreography. Calling it while an animation is in progress cancels the in-flight animation first, so it is safe to call repeatedly without debouncing.

// Single animation with await
await document.getElementById('my-surface').animate('bounce');
console.log('bounce complete');

// Sequential choreography across two surfaces
const surfaceA = document.getElementById('surface-a');
const surfaceB = document.getElementById('surface-b');

await surfaceA.animate('flash');
await surfaceB.animate('tada');

Nesting surfaces for layout control

Surfaces are transparent by default, so nesting them adds no visual overhead. Inner surfaces act purely as padding shims, giving you fine control over where inset applies without adding extra background layers.

Full-bleed list with padded search bar

An outer surface provides the border and vertical inset. An inner surface adds horizontal padding only to the search bar, leaving the list full-bleed.

Item one
Item two
<q2-surface radius="2" elevation="1" border="default" inset-y="normal" background="default">
    <!-- Search bar gets horizontal padding only -->
    <q2-surface inset-x="normal">
        <q2-input label="Search" hide-label type="search" placeholder="Search"></q2-input>
    </q2-surface>

    <!-- List is full-bleed - no horizontal inset -->
    <q2-list bordered>
        <q2-item><div slot="header">Item one</div></q2-item>
        <q2-item><div slot="header">Item two</div></q2-item>
    </q2-list>
</q2-surface>

Vertical spacers between content sections

Inner surfaces with inset-y create breathing room between content sections without adding a background or border.

Subject: Security Alert

From: bank@example.com

Dear customer, we noticed unusual activity...


Response

<q2-surface border="default" inset="normal" radius="2" background="default">
    <h3>Subject: Security Alert</h3>

    <!-- Metadata block -->
    <q2-surface radius="2" border="default" inset="normal">
        <p>From: bank@example.com</p>
    </q2-surface>

    <!-- Spacer between metadata and body -->
    <q2-surface inset-y="normal">
        <p>Dear customer, we noticed unusual activity...</p>
    </q2-surface>

    <hr />

    <!-- Spacer before reply section -->
    <q2-surface inset-y="normal">
        <h3>Response</h3>
        <q2-textarea></q2-textarea>
    </q2-surface>
</q2-surface>

Accessibility

Accessibility Report

Tecton components are designed and tested to be WCAG compliant when used appropriately, and do not get released without proper validation. Developers should prefer not to set ARIA attributes when using components from the Tecton Design System.

CSS Variables

The following CSS variables are available to override the default theme styles of the q2-surface component.

Changelog

The changelog provides a detailed history of new features, improvements, and bug fixes going back to Tecton 1.30.0. If the button is disabled, it indicates there have been no detectable changes since then.

Show changelog (1)