Skip to content
    Style: Wireframe

    Blocks · Marketing

    Plain tiles

    A heading and two lines of text on a quiet surface, nothing else; three across, stacked on narrow widths.

    74% of the 2,073 sites in The UI Index have a card (1,540 sites).

    What you get

    • Fast deploys

      Push to main and the site is live before you have switched tabs. Every branch gets its own preview link.

    • One-click rollback

      Pick any earlier deploy and make it live again. Nothing is rebuilt, so nothing can fail on the way back.

    • Quiet by default

      No dashboards to learn and no config to babysit. Read the log if you want to; most weeks you will not.

    Both previews render the same markup; the HTML tab below is that markup without a framework.

    Install

    React
    npx shadcn@latest add https://www.themes.dev/ui/r/plain-tiles.json
    Astro
    npx shadcn@latest add https://www.themes.dev/ui/r/astro/plain-tiles.json

    Or copy the files below into your project. They need clsx, tailwind-merge and the components they import, and the themes.dev UI theme. The HTML needs only the compiled CSS.

    plain-tiles.classes.ts
    /** Plain tiles: a heading and two lines of text on a quiet surface, nothing else (no picture, no link, no icon).
     *  Three across from 48rem of the block's own width, one under the other below it; tiles of a row share a height.
     *  The tiles are not interactive, so they have no hover or pressed treatment. */
    export const plainTiles = {
      root: '@container bg-background px-6 py-12 text-foreground @sm:py-16',
      inner: 'mx-auto max-w-6xl',
      heading: 'mb-8 text-2xl font-semibold tracking-[-0.02em] text-balance',
      list: 'm-0 grid list-none gap-4 p-0 @3xl:grid-cols-3 @3xl:gap-6',
      item: 'flex',
      tile: 'flex w-full min-w-0 flex-col gap-3 rounded-xl border bg-card p-6 text-card-foreground',
      title: 'text-lg leading-snug font-semibold tracking-[-0.01em] text-balance',
      text: 'text-base text-pretty text-muted-foreground',
    };
    
    export type Tile = { title: string; text: string };
    plain-tiles.tsx
    import { cn } from '@/lib/utils';
    import { plainTiles as c, type Tile } from './plain-tiles.classes';
    
    export type PlainTilesProps = { label?: string; title?: string; tiles: Tile[]; id?: string; className?: string };
    
    /** Plain tiles: a heading and two lines of text each, three across, stacked on narrow widths. */
    export function PlainTiles({ label = 'Highlights', title, tiles, id = 'plain-tiles', className }: PlainTilesProps) {
      return (
        <section id={id} aria-label={title ? undefined : label} aria-labelledby={title ? `${id}-title` : undefined} className={cn(c.root, className)}>
          <div className={c.inner}>
            {title && <h2 className={c.heading} id={`${id}-title`}>{title}</h2>}
            <ul className={c.list}>
              {tiles.map((t) => (
                <li key={t.title} className={c.item}>
                  <div className={c.tile}>
                    <h3 className={c.title}>{t.title}</h3>
                    <p className={c.text}>{t.text}</p>
                  </div>
                </li>
              ))}
            </ul>
          </div>
        </section>
      );
    }