diff --git a/src/components/Resource/README.md b/src/components/Resource/README.md
new file mode 100644
index 00000000000..e2f6f4d8b44
--- /dev/null
+++ b/src/components/Resource/README.md
@@ -0,0 +1,106 @@
+# ResourceGrid
+
+## What it does
+
+This component displays a grid of resource cards. Each card can represent either an article or a video, with an optional image, title, description, and link. Article cards show a "Read the full article" footer with an arrow.
+
+## How to use it
+
+1. Import the component in your Astro layout or page:
+
+```astro
+import ResourceGrid from "~/components/Resource/ResourceGrid.astro" import type {ResourceItem} from "~/components/Resource/ResourceGrid.astro"
+```
+
+2. (Optional) If you want to use imported images, import them:
+
+```astro
+import myImage from "~/assets/images/my-image.png"
+```
+
+3. Create an array of resources with the information for each resource card
+
+4. Add the component to your page and pass in the resources:
+
+```astro
+
+```
+
+## Example
+
+Here's a complete example showing how to use the component:
+
+```astro
+---
+import ResourceGrid from "~/components/Resource/ResourceGrid.astro"
+import type { ResourceItem } from "~/components/Resource/ResourceGrid.astro"
+import tokenPoolImage from "~/assets/images/token-pool.png"
+
+const resources: ResourceItem[] = [
+ {
+ image: tokenPoolImage,
+ imageAlt: "Token Pool illustration",
+ label: "Token Pool Types",
+ description:
+ "Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs.",
+ link: "/resources/token-pool-types",
+ type: "article",
+ },
+ {
+ label: "Getting Started with CCIP",
+ description:
+ "Learn how to build cross-chain applications using Chainlink CCIP in this comprehensive video tutorial.",
+ link: "https://youtube.com/watch?v=example",
+ type: "video",
+ },
+ {
+ image: "/images/cross-chain-messaging.png",
+ imageAlt: "Cross-chain messaging diagram",
+ label: "Understanding Cross-Chain Messaging",
+ description: "A deep dive into how cross-chain messaging works and how to implement it in your smart contracts.",
+ link: "/resources/cross-chain-messaging",
+ type: "article",
+ },
+]
+---
+
+
+```
+
+## What you need to provide
+
+Each item in your `resources` array needs these fields:
+
+| Field | Required? | What it is | Example |
+| --------------- | --------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------- |
+| **label** | Yes | The title of the resource | `"Token Pool Types"` |
+| **link** | Yes | Where the card should link to (can be internal or external) | `"/resources/token-pool-types"` or `"https://youtube.com/..."` |
+| **description** | Yes | A description explaining what the resource covers | `"Explore the various token pool types..."` |
+| **type** | Yes | The type of resource - either `"article"` or `"video"` | `"article"` |
+| **image** | No | Either an imported image or a path string | `myImage` (imported) or `"/images/token-pool.png"` (string path) |
+| **imageAlt** | No | Description of the image for accessibility (required if image is provided) | `"Token Pool illustration"` |
+
+## Where to put images
+
+Images are optional for resource cards. You have two options:
+
+### Option 1: Import images (recommended for images in your project)
+
+1. Place your image file in the `src/assets/images/` directory
+2. Import it at the top of your file:
+ ```astro
+ import myImage from "~/assets/images/my-image.png"
+ ```
+3. Use the imported variable in your resource object
+
+### Option 2: Use a path string (for public directory or external images)
+
+1. Place your image file in the `/public/images/` directory
+2. Reference it with the full path starting with `/images/`
+
+Both approaches work! Use imported images for better optimization, or use path strings for simplicity.
+
+## Resource types
+
+- **article**: Displays "Read the full article" footer with an arrow icon
+- **video**: No special footer (just the card with title and description)
diff --git a/src/components/Resource/ResourceCard.astro b/src/components/Resource/ResourceCard.astro
new file mode 100644
index 00000000000..e3ef42de9d4
--- /dev/null
+++ b/src/components/Resource/ResourceCard.astro
@@ -0,0 +1,47 @@
+---
+import { Typography, SvgArrowRight2 } from "@chainlink/blocks"
+import type { ImageMetadata } from "astro"
+import styles from "./ResourceCard.module.css"
+
+interface Props {
+ image?: string | ImageMetadata
+ imageAlt?: string
+ label: string
+ link: string
+ description: string
+ type: "article" | "video"
+}
+
+const { image, imageAlt, label, link, description, type } = Astro.props
+
+const imageSrc = typeof image === "string" ? image : image?.src
+---
+
+
+ {
+ imageSrc && (
+
+

+
+ )
+ }
+
+ {label}
+
+ {description}
+
+
+ {
+ type === "article" && (
+
+ )
+ }
+
diff --git a/src/components/Resource/ResourceCard.module.css b/src/components/Resource/ResourceCard.module.css
new file mode 100644
index 00000000000..475a298cbad
--- /dev/null
+++ b/src/components/Resource/ResourceCard.module.css
@@ -0,0 +1,79 @@
+.card {
+ display: flex;
+ flex-direction: column;
+ background: var(--color-background);
+ padding: var(--space-6x);
+ gap: var(--space-4x);
+ border-right: 1px solid var(--border);
+ border-bottom: 1px solid var(--border);
+ text-decoration: none;
+ transition: background-color 0.2s;
+ min-height: 329px;
+ cursor: default;
+}
+
+.card:nth-child(-n + 3) {
+ border-top: 1px solid var(--border);
+}
+
+.card:hover {
+ background-color: var(--muted);
+}
+
+.imageWrapper {
+ width: 100%;
+ aspect-ratio: 16 / 9;
+ overflow: hidden;
+ border-radius: var(--space-2x);
+}
+
+.image {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
+
+.content {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+}
+
+.cardLabel {
+ font-size: 16px;
+ font-weight: 525;
+ color: var(--foreground);
+ margin-bottom: var(--space-2x);
+}
+
+.cardFooter {
+ display: flex;
+ align-items: center;
+ width: 100%;
+ gap: var(--space-2x);
+ margin-top: var(--space-4x);
+}
+
+.footerText {
+ font-size: 14px;
+ color: var(--color-text-secondary);
+}
+@media screen and (max-width: 1024px) {
+ .card:nth-child(-n + 3) {
+ border-top: none;
+ }
+
+ .card:nth-child(-n + 2) {
+ border-top: 1px solid var(--border);
+ }
+}
+
+@media screen and (max-width: 768px) {
+ .card:nth-child(n) {
+ border-top: none;
+ }
+
+ .card:nth-child(1) {
+ border-top: 1px solid var(--border);
+ }
+}
diff --git a/src/components/Resource/ResourceGrid.astro b/src/components/Resource/ResourceGrid.astro
new file mode 100644
index 00000000000..1ec37d2aac1
--- /dev/null
+++ b/src/components/Resource/ResourceGrid.astro
@@ -0,0 +1,24 @@
+---
+import type { ImageMetadata } from "astro"
+import ResourceCard from "./ResourceCard.astro"
+import styles from "./ResourceGrid.module.css"
+
+export interface ResourceItem {
+ image?: string | ImageMetadata
+ imageAlt?: string
+ label: string
+ link: string
+ description: string
+ type: "article" | "video"
+}
+
+interface Props {
+ resources: ResourceItem[]
+}
+
+const { resources } = Astro.props
+---
+
+
+ {resources.map((resource) => )}
+
diff --git a/src/components/Resource/ResourceGrid.module.css b/src/components/Resource/ResourceGrid.module.css
new file mode 100644
index 00000000000..02cb548eeb9
--- /dev/null
+++ b/src/components/Resource/ResourceGrid.module.css
@@ -0,0 +1,17 @@
+.grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ border-left: 1px solid var(--border);
+}
+
+@media (max-width: 1024px) {
+ .grid {
+ grid-template-columns: repeat(2, 1fr);
+ }
+}
+
+@media (max-width: 768px) {
+ .grid {
+ grid-template-columns: 1fr;
+ }
+}
diff --git a/src/components/Resource/ResourceSection.astro b/src/components/Resource/ResourceSection.astro
new file mode 100644
index 00000000000..148f2b2213d
--- /dev/null
+++ b/src/components/Resource/ResourceSection.astro
@@ -0,0 +1,23 @@
+---
+import { Typography } from "@chainlink/blocks"
+import ResourceGrid from "./ResourceGrid.astro"
+import type { ResourceItem } from "./ResourceGrid.astro"
+import styles from "./ResourceSection.module.css"
+
+interface Props {
+ title: string
+ resources: ResourceItem[]
+}
+
+const { title, resources } = Astro.props
+---
+
+
diff --git a/src/components/Resource/ResourceSection.module.css b/src/components/Resource/ResourceSection.module.css
new file mode 100644
index 00000000000..13896ba6e6c
--- /dev/null
+++ b/src/components/Resource/ResourceSection.module.css
@@ -0,0 +1,6 @@
+.section {
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-8x);
+ margin: 56px 0;
+}
diff --git a/src/components/TabGrid/TabGrid.tsx b/src/components/TabGrid/TabGrid.tsx
index 6e85ec3cfa6..ab4962bc6e8 100644
--- a/src/components/TabGrid/TabGrid.tsx
+++ b/src/components/TabGrid/TabGrid.tsx
@@ -18,7 +18,14 @@ export const TabGrid = ({ tabs, header, columns = 3 }: TabGridProps) => {
return (
- {header}
+
+ {header}
+
{tabs.map((tab) => (
diff --git a/src/layouts/DocsV3Layout/DocsV3Layout.astro b/src/layouts/DocsV3Layout/DocsV3Layout.astro
index d9377a1ee8b..e22c08c265b 100644
--- a/src/layouts/DocsV3Layout/DocsV3Layout.astro
+++ b/src/layouts/DocsV3Layout/DocsV3Layout.astro
@@ -8,6 +8,7 @@ import LeftSidebar from "~/components/LeftSidebar/LeftSidebar.astro"
import PageContent from "~/components/PageContent/PageContent.astro"
import { TabGrid } from "~/components/TabGrid/TabGrid"
import LayoutHero from "~/components/LayoutHero/LayoutHero.astro"
+import ResourceSection from "~/components/Resource/ResourceSection.astro"
import MediaSection from "~/components/MediaSection/MediaSection.astro"
import QuickLinkCard from "~/components/QuickLinkCard/QuickLinkCard.astro"
import {
@@ -40,6 +41,31 @@ const currentPage = new URL(Astro.request.url).pathname
const includeLinkToWalletScript = !!Astro.props.frontmatter.metadata?.linkToWallet
+// Example resources data
+const exampleResources = [
+ {
+ label: "Token Pool Types",
+ description:
+ "Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs. Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs...",
+ link: "/resources/token-pool-types",
+ type: "article",
+ },
+ {
+ label: "Token Pool Types",
+ description:
+ "Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs. Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs...",
+ link: "/resources/token-pool-types",
+ type: "article",
+ },
+ {
+ label: "Token Pool Types",
+ description:
+ "Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs. Explore the various token pool types supported by the Cross-Chain Token (CCT) standard with Chainlink Labs...",
+ link: "/resources/token-pool-types",
+ type: "article",
+ },
+]
+
// Example tutorial data
const exampleTutorials = [
{
@@ -188,6 +214,8 @@ const quickLinks = [
]}
image="/images/ccip/ccip-hero.png"
/>
+
+