Skip to content
Facade UI
Colour mode
GitHub (opens in a new tab)
uiatom

Feature icon

The tinted container an icon sits in. Takes an icon component and hides it from assistive tech.

Preview

Open full width (opens in a new tab)
Preview width

Installation

Package manager
pnpm dlx shadcn@latest add https://facadeui.dev/r/feature-icon.json

Pulls in class-variance-authority@^0.7.1, types, utils. The CLI installs them for you.

Usage

The exact source of the preview above.

demos/feature-icon.tsx
import { BoltIcon, LockIcon, RocketIcon, WaypointsIcon } from "lucide-react"

import { FeatureIcon } from "@registry/ui/feature-icon"

export function Demo() {
  return (
    <div className="flex flex-wrap items-center gap-6">
      <FeatureIcon icon={BoltIcon} />
      <FeatureIcon icon={LockIcon} variant="solid" shape="circle" />
      <FeatureIcon icon={RocketIcon} variant="outline" size="lg" />
      <FeatureIcon icon={WaypointsIcon} variant="plain" />
    </div>
  )
}

Source

What the CLI copies into your project, byte for byte.

components/ui/feature-icon.tsx
/**
 * FeatureIcon — the tinted container an icon sits in on feature cards.
 *
 * Takes an icon *component* rather than a rendered node so it can apply sizing
 * and `aria-hidden` itself. That removes the most common a11y slip in marketing
 * UI: a decorative icon that is announced because the author forgot to hide it.
 *
 * a11y: the icon is always `aria-hidden` — its meaning is carried by the heading
 * beside it. If an icon is the *only* content conveying something, it does not
 * belong here; use a labelled element instead.
 *
 * Dependencies: class-variance-authority, react, @/lib/types, @/lib/utils.
 */

import { cva, type VariantProps } from "class-variance-authority"
import type { ElementType } from "react"

import type { IconComponent } from "@/lib/types"
import { cn } from "@/lib/utils"

export const featureIconVariants = cva(
  "inline-flex shrink-0 items-center justify-center",
  {
    variants: {
      variant: {
        soft: "bg-accent text-accent-foreground",
        solid: "bg-primary text-primary-foreground",
        outline: "border-border bg-background text-foreground border",
        plain: "text-primary",
      },
      size: {
        sm: "size-9 [&_svg]:size-4",
        md: "size-11 [&_svg]:size-5",
        lg: "size-14 [&_svg]:size-6",
      },
      shape: {
        rounded: "rounded-lg",
        circle: "rounded-full",
        square: "rounded-none",
      },
    },
    compoundVariants: [{ variant: "plain", class: "size-auto bg-transparent" }],
    defaultVariants: { variant: "soft", size: "md", shape: "rounded" },
  },
)

export interface FeatureIconProps extends VariantProps<typeof featureIconVariants> {
  icon: IconComponent
  className?: string
}

export function FeatureIcon({ icon, variant, size, shape, className }: FeatureIconProps) {
  const Icon = icon as ElementType

  return (
    <span className={cn(featureIconVariants({ variant, size, shape }), className)}>
      <Icon aria-hidden focusable="false" />
    </span>
  )
}

Props

FeatureIconProps

Extends VariantProps<typeof featureIconVariants>.

Props for FeatureIconProps
PropTypeDefault
icon*RequiredIconComponent
classNamestring