# Feature 05

> Values section: a centered header over a two-column, offset grid of six glass cards, each backed by a static dot pattern in the primary color, rising in with a staggered CSS entrance.

A shadcn/ui block from the [@hirael](https://hirael.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/hirael/feature-05).

- Page, with a live preview: https://shadcn.exchange/r/hirael/feature-05
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/hirael/feature-05-light-514f1d2c4f5112f6.png
- Registry item: https://hirael.com/r/feature-05.json
- Categories: blocks, feature
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://hirael.com/r/feature-05.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `badge`

## Files

### `registry/hirael/bases/radix/blocks/feature-05/feature-05.tsx`

```tsx
// Feature 05 from Hirael <https://hirael.com/blocks/features/feature-05>
// MIT · Mohammad Shehadeh · https://github.com/MohammadShehadeh/hirael

import type * as React from 'react';

import { cn } from '@/lib/utils';
import { Badge } from '@/registry/hirael/bases/radix/ui/badge';

const RISE =
  'animate-in fade-in slide-in-from-bottom-4 duration-500 ease-[cubic-bezier(0.22,1,0.36,1)] fill-mode-both motion-reduce:animate-none';

const stagger = (index: number, step = 60, offset = 0): React.CSSProperties => ({
  animationDelay: `${offset + index * step}ms`,
});

interface Value {
  title: string;
  description: string;
}

const VALUES: readonly Value[] = [
  {
    title: 'Own the source',
    description: 'Every component installs as plain TypeScript in your repo. No package to pin, nothing to wait on.',
  },
  {
    title: 'Accessible by default',
    description:
      'Keyboard paths, focus rings, and screen reader labels are part of the component, not a follow-up ticket.',
  },
  {
    title: 'Tokens over hex',
    description:
      'One set of CSS variables drives light, dark, and any brand you bring. Change the token, change the product.',
  },
  {
    title: 'Compound first',
    description: 'Small parts you arrange yourself, named and composed the way shadcn/ui primitives are.',
  },
  {
    title: 'RTL without config',
    description:
      'Logical properties and mirrored icons mean Arabic and Hebrew layouts work the day you flip the direction.',
  },
  {
    title: 'Plain language',
    description: 'Labels, empty states, and docs read like a person wrote them. Short, specific, no hype.',
  },
];

const Title = () => {
  return (
    <h2
      data-slot="feature-title"
      style={stagger(1)}
      className={cn(RISE, 'font-serif text-4xl leading-[1.04] font-medium tracking-tight text-balance sm:text-5xl')}
    >
      The principles behind every component
    </h2>
  );
};

interface DottedGlowProps {
  className?: string;
}

const DottedGlow = ({ className }: DottedGlowProps) => {
  return (
    <div
      aria-hidden
      data-slot="dotted-glow"
      className={cn(
        'pointer-events-none absolute inset-0 bg-[radial-gradient(var(--primary)_1.6px,transparent_1.6px)] [mask-image:radial-gradient(ellipse_at_center,black,transparent_80%)] bg-size-[10px_10px] opacity-40',
        className,
      )}
    />
  );
};

interface ValueCardProps {
  value: Value;
  index: number;
}

const ValueCard = ({ value, index }: ValueCardProps) => {
  return (
    <article
      data-slot="feature-card"
      style={stagger(index, 60, 180)}
      className={cn(RISE, 'relative overflow-hidden rounded-lg border border-border bg-card/60 p-6 backdrop-blur-sm')}
    >
      <DottedGlow />
      <div className="relative flex flex-col gap-2">
        <h3 className="text-xl font-semibold text-foreground">{value.title}</h3>
        <p className="text-pretty text-muted-foreground">{value.description}</p>
      </div>
    </article>
  );
};

const Feature05 = () => {
  const half = Math.ceil(VALUES.length / 2);
  const columns = [VALUES.slice(0, half), VALUES.slice(half)];

  return (
    <section data-slot="feature" className="bg-background py-20 sm:py-28">
      <div className="mx-auto w-full max-w-[1480px] px-4">
        <div data-slot="feature-header" className="mx-auto flex max-w-2xl flex-col items-center gap-5 text-center">
          <div className={RISE}>
            <Badge variant="outline">Values</Badge>
          </div>
          <Title />
          <p
            data-slot="feature-description"
            style={stagger(2)}
            className={cn(RISE, 'max-w-2xl text-base text-pretty text-muted-foreground sm:text-lg')}
          >
            Six decisions we make the same way every time, so you never have to guess how a new component will behave.
          </p>
        </div>

        <div
          data-slot="feature-grid"
          className="mx-auto mt-14 grid w-full max-w-5xl grid-cols-1 gap-4 md:grid-cols-2 md:gap-8"
        >
          {columns.map((column, c) => (
            <div
              key={c}
              data-slot="feature-column"
              className={cn('flex flex-col gap-4 md:gap-8', c === 1 && 'md:mt-16')}
            >
              {column.map((value, i) => (
                <ValueCard key={value.title} value={value} index={c * half + i} />
              ))}
            </div>
          ))}
        </div>
      </div>
    </section>
  );
};

export default Feature05;
```
