Skip to content

NeoGridBox Component

The NeoGridBox component allows you to create a responsive grid of boxes, each with an image, title, description, and link. You can customize the size, colors, and behavior of each box, and the grid will adjust automatically.

Installation

Include the NeoGridBox component in the VitePress installation and register it (globally or per scope, but globally is the most comfortable option).

js
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
import NeoNeoGridBox from './components/NeoGridBox.vue'

export default {
    extends: DefaultTheme,
    enhanceApp({app}) {
        app.component('NeoGridBox', NeoGridBox)
    }
}

Basic usage

The NeoGridBox component accepts an array of items via the :items prop. Each item can have several properties such as title, description, image, and link.

vue
<NeoGridBox :items="[
  {
    title: 'Box 1',
    description: 'This is the first box with an explanatory description.',
    image: '/images/icon/firewall.png',
    link: '#',
    linkText: 'More information'
  },
  {
    title: 'Box 2',
    description: 'This is the second box with a different description.',
    image: '/images/branding/icon/blue-transparent.svg',
    link: '#',
    linkText: 'View details'
  },
  {
    title: 'Box 3',
    description: 'This is the third box with another description.',
    image: 'https://api.iconify.design/mdi/rocket-launch.svg?height=512&color=%234a6cf7',
    link: '#',
    linkText: 'Get started'
  }
]" />
Box 1

Box 1

This is the first box with an explanatory description.

Box 2

Box 2

This is the second box with a different description.

Box 3

Box 3

This is the third box with another description.

Customizing the grid layout

You can customize the number of columns and the space between the boxes:

vue
<NeoGridBox 
  :columns="2" 
  gap="2rem"
  :items="[
    {
      title: 'Box 1',
      description: 'This box uses the default size.',
      image: '/images/icon/firewall.png',
      link: '#',
      linkText: 'More information'
    },
    {
      title: 'Box 2',
      description: 'This box uses the default size.',
      image: '/images/branding/icon/blue-transparent.svg',
      link: '#',
      linkText: 'View details'
    }
  ]" 
/>
Box 1

Box 1

This box uses the default size.

Box 2

Box 2

This box uses the default size.

Custom sizes

You can specify the size of each box using the size prop:

vue
<NeoGridBox 
  :columns="3" 
  :items="[
    {
      title: 'Large box',
      description: 'This box occupies 2 columns and 1 row.',
      image: '/images/icon/firewall.png',
      link: '#',
      linkText: 'More information',
      size: { cols: 2, rows: 1 }
    },
    {
      title: 'Small box',
      description: 'This box uses the default size.',
      image: '/images/branding/icon/blue-transparent.svg',
      link: '#',
      linkText: 'View details'
    },
    {
      title: 'Tall box',
      description: 'This box occupies 1 column and 2 rows. It has more content to demonstrate how it expands vertically.',
      image: 'https://api.iconify.design/mdi/rocket-launch.svg?height=512&color=%234a6cf7',
      link: '#',
      linkText: 'Get started',
      size: { cols: 1, rows: 2 }
    },
    {
      title: 'Regular box',
      description: 'This box uses the default size.',
      image: '/images/icon/firewall.png',
      link: '#',
      linkText: 'More information'
    }
  ]" 
/>
Large box

Large box

This box occupies 2 columns and 1 row.

Small box

Small box

This box uses the default size.

Tall box

Tall box

This box occupies 1 column and 2 rows. It has more content to demonstrate how it expands vertically.

Regular box

Regular box

This box uses the default size.

Custom colors

You can customize the colors of each box or use the default VitePress colors:

vue
<NeoGridBox 
  :columns="3" 
  :items="[
    {
      title: 'Default background',
      description: 'This box uses the default VitePress background color (--vp-c-bg-soft).',
      image: '/images/icon/firewall.png',
      link: '#',
      linkText: 'More information'
    },
    {
      title: 'Custom background',
      description: 'This box has a custom background color.',
      image: '/images/branding/icon/blue-transparent.svg',
      link: '#',
      linkText: 'View details',
      backgroundColor: '#f0f8ff'
    },
    {
      title: 'Custom title color',
      description: 'This box has a custom title color.',
      image: 'https://api.iconify.design/mdi/rocket-launch.svg?height=128&color=%234a6cf7',
      link: '#',
      linkText: 'Get started',
      titleColor: '#e63946'
    },
    {
      title: 'Custom text color',
      description: 'This box has a custom text color for the description.',
      image: '/images/icon/firewall.png',
      link: '#',
      linkText: 'More information',
      textColor: '#2a9d8f'
    },
    {
      title: 'Custom link color',
      description: 'This box has a custom link color.',
      image: '/images/branding/icon/blue-transparent.svg',
      link: '#',
      linkText: 'View details',
      linkColor: '#6a0dad'
    },
    {
      title: 'All custom colors',
      description: 'This box has all custom colors.',
      image: 'https://api.iconify.design/mdi/rocket-launch.svg?color=%234a6cf7',
      link: '#',
      linkText: 'Get started',
      backgroundColor: '#264653',
      titleColor: '#e9c46a',
      textColor: '#f4a261',
      linkColor: '#e76f51'
    }
  ]" 
/>
Default background

Default background

This box uses the default VitePress background color (--vp-c-bg-soft).

Custom background

Custom background

This box has a custom background color.

Custom title color

Custom title color

This box has a custom title color.

Custom text color

Custom text color

This box has a custom text color for the description.

Custom link color

Custom link color

This box has a custom link color.

All custom colors

All custom colors

This box has all custom colors.

External URLs as images

You can now use external URLs as images for the boxes, allowing you to load SVGs or images from APIs or external CDNs:

vue
<NeoGridBox 
  :columns="3" 
  :items="[
    {
      title: 'Icon from external API',
      description: 'This box loads an SVG icon from the Iconify API.',
      image: 'https://api.iconify.design/bi/bell-fill.svg?height=16&color=%23ba3329',
      link: '#',
      linkText: 'More information'
    },
    {
      title: 'Normal local image',
      description: 'This box still uses a local image with a relative path.',
      image: '/images/branding/icon/blue-transparent.svg',
      link: '#',
      linkText: 'View details'
    },
    {
      title: 'Another external icon',
      description: 'Another example of an icon from Iconify with a different color.',
      image: 'https://api.iconify.design/mdi/rocket-launch.svg?color=%234a6cf7',
      link: '#',
      linkText: 'Get started',
      imageSize: 80
    }
  ]"
/>
Icon from external API

Icon from external API

This box loads an SVG icon from the Iconify API.

Normal local image

Normal local image

This box still uses a local image with a relative path.

Another external icon

Another external icon

Another example of an icon from Iconify with a different color.

Interactive features

You can customize the interactive behavior of each box:

vue
<NeoGridBox
  :columns="3"
  :items="[
    {
      title: 'No hover effect',
      description: 'This box has the hover effect disabled.',
      image: '/images/icon/firewall.png',
      link: '#',
      linkText: 'More information',
      disableHoverEffect: true
    },
    {
      title: 'Background change on hover',
      description: 'This box changes the background color when hovering.',
      image: '/images/branding/icon/blue-transparent.svg',
      link: '#',
      linkText: 'View details',
      hoverBackgroundColor: '#e0f7fa'
    },
    {
      title: 'Fully clickable box',
      description: 'The entire box is clickable, not just the link.',
      image: 'https://api.iconify.design/mdi/rocket-launch.svg?color=%234a6cf7',
      link: '#',
      linkText: 'Get started',
      fullBoxClickable: true
    },
    {
      title: 'Combined features',
      description: 'This box changes the background on hover and is fully clickable.',
      image: '/images/icon/firewall.png',
      link: '#',
      linkText: 'More information',
      hoverBackgroundColor: '#fff8e1',
      fullBoxClickable: true
    }
  ]"
/>

Text color change on hover

You can control whether the text color changes when hovering over fully clickable boxes:

vue
<NeoGridBox
  :columns="3"
  :items="[
    {
      title: 'Default behavior',
      description: 'This box changes the text color on hover (default behavior).',
      image: '/images/icon/firewall.png',
      link: '#',
      linkText: 'More information',
      fullBoxClickable: true
    },
    {
      title: 'Custom hover text color',
      description: 'This box uses a custom hover text color.',
      image: '/images/branding/icon/blue-transparent.svg',
      link: '#',
      linkText: 'View details',
      fullBoxClickable: true,
      hoverTextColor: '#e63946'
    },
    {
      title: 'Color change disabled',
      description: 'This box does not change the text color on hover.',
      image: 'https://api.iconify.design/mdi/rocket-launch.svg?color=%234a6cf7',
      link: '#',
      linkText: 'Get started',
      fullBoxClickable: true,
      hoverTextColor: false
    }
  ]"
/>

Sizes and alignment of elements

You can customize the size and alignment of each element:

vue
<NeoGridBox
  :columns="3"
  :items="[
    {
      title: 'Custom image size',
      description: 'This box has a larger image.',
      image: '/images/icon/firewall.png',
      link: '#',
      linkText: 'More information',
      imageSize: 100
    },
    {
      title: 'Custom title size and alignment',
      description: 'This box has a larger title aligned to the right.',
      image: '/images/branding/icon/blue-transparent.svg',
      link: '#',
      linkText: 'View details',
      titleSize: 24,
      titleAlign: 'right'
    },
    {
      title: 'Custom description size and alignment',
      description: 'This box has a larger description text aligned to the left.',
      image: 'https://api.iconify.design/mdi/rocket-launch.svg?color=%234a6cf7',
      link: '#',
      linkText: 'Get started',
      textSize: 18,
      textAlign: 'left'
    },
    {
      title: 'Custom link size and alignment',
      description: 'This box has a larger link aligned to the center.',
      image: '/images/icon/firewall.png',
      link: '#',
      linkText: 'More information',
      linkSize: 18,
      linkAlign: 'center'
    },
    {
      title: 'Image aligned to the left',
      description: 'This box has the image aligned to the left.',
      image: '/images/branding/icon/blue-transparent.svg',
      link: '#',
      linkText: 'View details',
      imageAlign: 'left'
    },
    {
      title: 'Image aligned to the right',
      description: 'This box has the image aligned to the right.',
      image: 'https://api.iconify.design/mdi/rocket-launch.svg?color=%234a6cf7',
      link: '#',
      linkText: 'Get started',
      imageAlign: 'right'
    }
  ]"
/>
Custom image size

Custom image size

This box has a larger image.

Custom title size and alignment

Custom title size and alignment

This box has a larger title aligned to the right.

Custom description size and alignment

Custom description size and alignment

This box has a larger description text aligned to the left.

Custom link size and alignment

Custom link size and alignment

This box has a larger link aligned to the center.

Image aligned to the left

Image aligned to the left

This box has the image aligned to the left.

Image aligned to the right

Image aligned to the right

This box has the image aligned to the right.

Optional elements

All elements are optional, so you can create boxes with only the elements you need:

vue
<NeoGridBox
  :columns="3"
  :items="[
    {
      title: 'Only image and title',
      image: '/images/icon/firewall.png'
    },
    {
      description: 'Only description',
    },
    {
      title: 'Only title and link',
      link: '#',
      linkText: 'More information'
    },
    {
      image: '/images/branding/icon/blue-transparent.svg',
      description: 'Only image and description'
    },
    {
      title: 'Title, description, and link',
      description: 'No image in this box.',
      link: '#',
      linkText: 'View details'
    }
  ]"
/>
Only image and title

Only image and title

Only description

Only title and link

Only image and description

Title, description, and link

No image in this box.

Vue components as icons

You can use Vue components as icons instead of images:

vue
<script setup>
import { h } from 'vue'

// Example of creating a simple icon component
const DiscordIcon = () => h('svg', {
  xmlns: 'http://www.w3.org/2000/svg',
  width: '24',
  height: '24',
  viewBox: '0 0 24 24',
  fill: 'currentColor',
  style: { color: '#5865F2' }
}, [
  h('path', { d: 'M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09-.01-.02-.04-.03-.07-.03-1.5.26-2.93.71-4.27 1.33-.01 0-.02.01-.03.02-2.72 4.07-3.47 8.03-3.1 11.95 0 .02.01.04.03.05 1.8 1.32 3.53 2.12 5.24 2.65.03.01.06 0 .07-.02.4-.55.76-1.13 1.07-1.74.02-.04 0-.08-.04-.09-.57-.22-1.11-.48-1.64-.78-.04-.02-.04-.08-.01-.11.11-.08.22-.17.33-.25.02-.02.05-.02.07-.01 3.44 1.57 7.15 1.57 10.55 0 .02-.01.05-.01.07.01.11.09.22.17.33.26.04.03.04.09-.01.11-.52.31-1.07.56-1.64.78-.04.01-.05.06-.04.09.32.61.68 1.19 1.07 1.74.03.02.06.03.09.02 1.72-.53 3.45-1.33 5.25-2.65.02-.01.03-.03.03-.05.44-4.53-.73-8.46-3.1-11.95-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12 0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12 0 1.17-.83 2.12-1.89 2.12z' })
])

// Example of creating a mail icon component
const MailIcon = () => h('svg', {
  xmlns: 'http://www.w3.org/2000/svg',
  width: '24',
  height: '24',
  viewBox: '0 0 24 24',
  fill: 'currentColor',
  style: { color: '#0288D1' }
}, [
  h('path', { d: 'M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z' })
])
</script>

<NeoGridBox
  :columns="3"
  :items="[
    {
      title: 'Discord Icon',
      description: 'This box uses a Vue component for the Discord icon.',
      component: DiscordIcon,
      link: '#',
      linkText: 'More information'
    },
    {
      title: 'Mail Icon',
      description: 'This box uses a Vue component for the Mail icon.',
      component: MailIcon,
      link: '#',
      linkText: 'View details'
    },
    {
      title: 'Custom icon size',
      description: 'This box uses a Vue component with a custom size.',
      component: DiscordIcon,
      link: '#',
      linkText: 'Get started',
      imageSize: 48
    }
  ]"
/>

Discord Icon

This box uses a Vue component for the Discord icon.

Mail Icon

This box uses a Vue component for the Mail icon.

Custom icon size

This box uses a Vue component with a custom size.

You can add an icon to your links (either to the left or right of the link text). There are two ways to do this:

  1. Use a custom SVG by providing the SVG code in the linkIcon property
  2. Set linkIcon to true to use the default arrow icon

By default, the icon appears to the right of the text, but you can change its position using the iconPosition property with values 'left' or 'right'.

vue
<NeoGridBox
  :columns="3"
  :items="[
    {
      title: 'Default icon (right side)',
      description: 'This box uses the default icon on the right side of the link.',
      image: '/images/icon/firewall.png',
      link: '#',
      linkText: 'More information',
      linkIcon: true
    },
    {
      title: 'Icon on the left side',
      description: 'This box has the icon on the left side of the link.',
      image: '/images/branding/icon/blue-transparent.svg',
      link: '#',
      linkText: 'View details',
      linkIcon: true,
      iconPosition: 'left'
    },
    {
      title: 'Custom SVG icon',
      description: 'This box uses a custom SVG as the link icon.',
      image: 'https://api.iconify.design/mdi/rocket-launch.svg?color=%234a6cf7',
      link: '#',
      linkText: 'Get started',
      linkIcon: '<svg>...</svg>'
    }
  ]"
/>
Default icon (right side)

Default icon (right side)

This box uses the default icon on the right side of the link.

Icon on the left side

Icon on the left side

This box has the icon on the left side of the link.

Custom SVG icon

Custom SVG icon

This box uses a custom SVG as the link icon.

Custom combinations

You can combine various properties to create unique designs:

vue
<NeoGridBox
  :columns="2"
  gap="1.5rem"
  :items="[
    {
      title: 'Complete design with customization',
      description: 'This box combines multiple properties to create a unique design.',
      image: '/images/branding/icon/blue-dark.svg',
      link: '#',
      linkText: 'Explore',
      size: { cols: 1, rows: 2 },
      backgroundColor: '#f8f9fa',
      titleColor: '#1e88e5',
      titleSize: 22,
      titleAlign: 'center',
      textSize: 16,
      textAlign: 'justify',
      linkColor: '#0d47a1',
      linkSize: 16,
      linkAlign: 'center',
      imageSize: 80,
      imageAlign: 'center',
      hoverBackgroundColor: '#e3f2fd'
    },
    {
      title: 'Clickable box with custom style',
      description: 'This box is fully clickable and has custom hover effects.',
      image: '/images/branding/icon/blue-light.svg',
      link: '#',
      linkText: 'Discover',
      fullBoxClickable: true,
      hoverBackgroundColor: '#e8f5e9',
      hoverTextColor: '#2e7d32',
      imageSize: 70,
      titleAlign: 'center',
      textAlign: 'center',
      linkAlign: 'center'
    },
    {
      title: 'Business design',
      description: 'A more sober and professional style for corporate environments.',
      image: '/images/branding/icon/blue-transparent.svg',
      link: '#',
      linkText: 'View solutions',
      backgroundColor: '#ffffff',
      titleColor: '#333333',
      textColor: '#666666',
      linkColor: '#1976d2',
      imageAlign: 'left',
      titleAlign: 'left',
      textAlign: 'left',
      hoverBackgroundColor: '#fafafa'
    },
    {
      title: 'Product card style',
      description: 'Design similar to a product card with hover effects.',
      image: '/images/branding/icon/white-dark.svg',
      link: '#',
      linkText: 'Buy now',
      fullBoxClickable: true,
      backgroundColor: '#ffffff',
      titleColor: '#212121',
      textColor: '#757575',
      linkColor: '#f44336',
      titleAlign: 'center',
      textAlign: 'center',
      linkAlign: 'center',
      hoverBackgroundColor: '#fafafa',
      hoverTextColor: '#f44336'
    }
  ]"
/>

## Custom combinations

You can combine various properties to create unique designs:

```vue:line-numbers {1}
<NeoGridBox
  :columns="2"
  gap="1.5rem"
  :items="[
    {
      title: 'Complete design with customization',
      description: 'This box combines multiple properties to create a unique design.',
      image: '/images/branding/icon/blue-dark.svg',
      link: '#',
      linkText: 'Explore',
      size: { cols: 1, rows: 2 },
      backgroundColor: '#f8f9fa',
      titleColor: '#1e88e5',
      titleSize: 22,
      titleAlign: 'center',
      textSize: 16,
      textAlign: 'justify',
      linkColor: '#0d47a1',
      linkSize: 16,
      linkAlign: 'center',
      imageSize: 80,
      imageAlign: 'center',
      hoverBackgroundColor: '#e3f2fd'
    },
    {
      title: 'Clickable box with custom style',
      description: 'This box is fully clickable and has custom hover effects.',
      image: '/images/branding/icon/blue-light.svg',
      link: '#',
      linkText: 'Discover',
      fullBoxClickable: true,
      hoverBackgroundColor: '#e8f5e9',
      hoverTextColor: '#2e7d32',
      imageSize: 70,
      titleAlign: 'center',
      textAlign: 'center',
      linkAlign: 'center'
    },
    {
      title: 'Business design',
      description: 'A more sober and professional style for corporate environments.',
      image: '/images/branding/icon/blue-transparent.svg',
      link: '#',
      linkText: 'View solutions',
      backgroundColor: '#ffffff',
      titleColor: '#333333',
      textColor: '#666666',
      linkColor: '#1976d2',
      imageAlign: 'left',
      titleAlign: 'left',
      textAlign: 'left',
      hoverBackgroundColor: '#fafafa'
    },
    {
      title: 'Product card style',
      description: 'Design similar to a product card with hover effects.',
      image: '/images/branding/icon/white-dark.svg',
      link: '#',
      linkText: 'Buy now',
      fullBoxClickable: true,
      backgroundColor: '#ffffff',
      titleColor: '#212121',
      textColor: '#757575',
      linkColor: '#f44336',
      titleAlign: 'center',
      textAlign: 'center',
      linkAlign: 'center',
      hoverBackgroundColor: '#fafafa',
      hoverTextColor: '#f44336'
    }
  ]"
/>
Complete design with customization

Complete design with customization

This box combines multiple properties to create a unique design.

Clickable box with custom style

Clickable box with custom style

This box is fully clickable and has custom hover effects.

Business design

Business design

A more sober and professional style for corporate environments.

Product card style

Product card style

Design similar to a product card with hover effects.

Vertical alignment

By default, all boxes have their content vertically centered. You can disable this behavior for specific boxes by setting the alignVertically property to false:

vue
<NeoGridBox
  :columns="3"
  :items="[
    {
      title: 'Default centered content',
      description: 'This box has the content vertically centered (default behavior).',
      image: '/images/icon/firewall.png',
      link: '#',
      linkText: 'More information'
    },
    {
      title: 'Vertical centering disabled',
      description: 'This box has the vertical centering disabled, so the content starts at the top.',
      image: '/images/branding/icon/blue-transparent.svg',
      link: '#',
      linkText: 'View details',
      alignVertically: false
    }
  ]"
/>
Default centered content

Default centered content

This box has the content vertically centered (default behavior).

Vertical centering disabled

Vertical centering disabled

This box has the vertical centering disabled, so the content starts at the top.

Component API

Props

PropTypeDefault valueDescription
itemsArray(required)Array of objects representing each box
columnsNumber3Number of columns in the grid
gapString'1.5rem'Space between grid elements

Item properties

Each item in the items array can have the following properties. Every property that accepts text can also accept HTML being injected into it:

PropertyTypeDescription
titleStringBox title
descriptionStringDescription text
imageStringPath to the image
componentComponentVue component to use as an icon instead of an image
linkStringURL for the link
linkTextStringText for the link
linkIconString/BooleanCustom SVG code for the link icon or true to use the default arrow icon
iconPositionStringPosition of the link icon. Can be 'left' or 'right' (default is 'right')
sizeObjectBox size, e.g., { cols: 2, rows: 1 }
backgroundColorStringCustom background color for the box
titleColorStringCustom color for the title
textColorStringCustom color for the description text
linkColorStringCustom color for the link
disableHoverEffectBooleanDisables the hover effect (elevation and shadow) when set to true (default true)
hoverBackgroundColorStringChanges the background color on hover to the specified color
fullBoxClickableBooleanMakes the entire box clickable, not just the link, when set to true
hoverTextColorString/BooleanCustom color for the text on hover when the box is fully clickable. Set to false to disable text color change on hover
imageSizeString/NumberCustom size for the image or icon. Can be a number (pixels) or a string (e.g., '50%')
imageAlignStringAlignment of the image or icon. Can be 'left', 'center', or 'right'
titleSizeString/NumberCustom size for the title. Can be a number (pixels) or a string (e.g., '1.5rem')
titleAlignStringAlignment of the title. Can be 'left', 'center', or 'right'
textSizeString/NumberCustom size for the description text. Can be a number (pixels) or a string (e.g., '1rem')
textAlignStringAlignment of the description text. Can be 'left', 'center', or 'right'
linkSizeString/NumberCustom size for the link. Can be a number (pixels) or a string (e.g., '0.9rem')
linkAlignStringAlignment of the link. Can be 'left', 'center', or 'right'
classNameStringAdditional CSS class name to be applied to the box
alignVerticallyBooleanControls vertical alignment of the content. Set to false to disable vertical centering (default is true)