Composable blocks
Ship complete sections without moving product copy, route decisions, or data ownership into the registry item.
Feature sections
Render a polished feature section from app-owned data while keeping icons, routes, analytics, and content sources under your control.
Ship complete sections without moving product copy, route decisions, or data ownership into the registry item.
Pass the exact feature list your product needs, from static arrays, CMS records, or localized copy.
Link selected features to deeper docs or marketing pages while preserving your app's navigation model.
Keep click tracking and campaign metadata in your app instead of coupling the block to one analytics tool.
Use the same data shape for landing pages, onboarding screens, docs overviews, and searchable feature indexes.
Blank-target feature links receive a safe default rel while still allowing app-specific rel overrides.
pnpm dlx shadcn-vue@latest add "https://ui.stackhacker.io/r/feature-grid.json"
<script setup lang="ts">
import type { Component } from 'vue'
import { Blocks, Route, Search } from 'lucide-vue-next'
import { FeatureGrid, type FeatureGridItem } from '@/components/feature-grid'
const features: FeatureGridItem[] = [
{
id: 'blocks',
title: 'Composable blocks',
description: 'Ship complete sections while keeping product data in your app.'
},
{
id: 'routing',
title: 'Route-ready links',
description: 'Link selected features to deeper pages without coupling the block to Nuxt routing.',
href: '/features'
},
{
id: 'search',
title: 'Discovery surfaces',
description: 'Use the same data shape for landing pages, docs overviews, and searchable indexes.'
}
]
const icons: Partial<Record<string, Component>> = {
blocks: Blocks,
routing: Route,
search: Search
}
function featureIcon(item: FeatureGridItem) {
return item.id ? icons[item.id] : undefined
}
</script>
<template>
<FeatureGrid
headline="Feature sections"
title="Product capabilities at a glance"
description="Render a polished feature section from app-owned data."
:items="features"
>
<template #icon="{ item }">
<component v-if="featureIcon(item)" :is="featureIcon(item)" class="size-5" aria-hidden="true" />
</template>
</FeatureGrid>
</template>FeatureGrid owns the full marketing section: optional headline, title, description, responsive grid layout, and repeated feature items. Use it when you want to install a complete section that can drop into a landing page, docs overview, or product page.
FeatureCard remains the smaller card primitive for one-off feature, content, or navigation cards. Use it when your app already owns the surrounding section layout or when you need to compose custom grids by hand.
Your app owns the items array, route generation, analytics events, active states, CMS mapping, localization, and icon rendering. The component intentionally does not accept Nuxt Icon string names, require NuxtLink, or install an icon package.
Pass icon markup through the scoped icon slot. That keeps the block portable across Lucide, Nuxt Icon, custom SVGs, or no icons at all.
When an item has href, it renders as an anchor. When href is omitted, it renders static article content. For target="_blank", the component adds rel="noopener noreferrer" unless you provide a custom rel value.
Feature sections
Render a polished feature section from app-owned data while keeping icons, routes, analytics, and content sources under your control.
Ship complete sections without moving product copy, route decisions, or data ownership into the registry item.
Pass the exact feature list your product needs, from static arrays, CMS records, or localized copy.
Link selected features to deeper docs or marketing pages while preserving your app's navigation model.
Keep click tracking and campaign metadata in your app instead of coupling the block to one analytics tool.
Use the same data shape for landing pages, onboarding screens, docs overviews, and searchable feature indexes.
Blank-target feature links receive a safe default rel while still allowing app-specific rel overrides.
| Prop | Type | Default | Description |
|---|---|---|---|
headline | string | — | Optional eyebrow label shown above the section title. |
title | string | — | Optional section title. |
description | string | — | Optional section description. |
items | FeatureGridItem[] | [] | Feature items supplied by your app. |
columns | 2 | 3 | 4 | 3 | Responsive column count for large screens. |
class | string | — | Additional CSS classes for the section. |
interface FeatureGridItem {
id?: string
title: string
description?: string
href?: string
target?: HTMLAnchorElement['target']
rel?: string
}| Slot | Props | Description |
|---|---|---|
icon | { item: FeatureGridItem } | Optional icon markup rendered above each item title. |