Skip to content

Instantly share code, notes, and snippets.

@mommaroodles
Last active April 28, 2025 15:56
Show Gist options
  • Select an option

  • Save mommaroodles/db53ce4ac18427b738d867cd9cce47f7 to your computer and use it in GitHub Desktop.

Select an option

Save mommaroodles/db53ce4ac18427b738d867cd9cce47f7 to your computer and use it in GitHub Desktop.
PayloadCMS - Add Icon Select to Blocks
My Implementation of adding a Select Icon Field to Blocks is quite simple. I add icons on demand as and when I need them instead of having the entire Icon Libary.
My PayloadCMS version: 3.35.1
Next.JS: 15.3.1
I'm using the PayloadCMS web site template.
// src/blocks/CoreFeatures/component.tsx
import React from 'react'
import { RenderIcon, IconName } from '@/components/Icons'
interface CoreFeaturesBlockProps {
heading?: string
subheading?: string
features: {
icon: IconName
title: string
description: string
id?: string
}[]
}
export const CoreFeatures: React.FC<CoreFeaturesBlockProps> = ({
heading = 'Our Core Features',
subheading = 'Features',
features = [],
}) => (
<section className="py-24">
<div className="container mx-auto max-w-screen-xl">
{subheading && <p className="mb-4 text-xs text-muted-foreground md:pl-5">{subheading}</p>}
<h2 className="text-3xl font-medium md:pl-5 lg:text-4xl">{heading}</h2>
<div className="mx-auto mt-14 grid gap-x-10 gap-y-8 md:grid-cols-2 lg:grid-cols-3">
{features.map((feature) => (
<div
className="flex flex-col items-start gap-4 rounded-lg bg-card p-6 shadow-sm"
key={feature.id || feature.title}
>
<span className="mb-4 flex size-12 items-center justify-center rounded-full bg-accent">
<RenderIcon name={feature.icon} className="size-5 md:size-7" />
</span>
<h3 className="font-medium text-lg">{feature.title}</h3>
<p className="text-sm text-muted-foreground">{feature.description}</p>
</div>
))}
</div>
</div>
</section>
)
export default CoreFeatures
// src/blocks/CoreFeatures/config.tsx
import type { Block } from 'payload'
import { availableIcons } from '@/components/Icons'
export type FeatureIconType = (typeof availableIcons)[number]['value']
export const CoreFeaturesBlock: Block = {
slug: 'corefeatures',
labels: {
singular: 'Core Feature',
plural: 'Core Features',
},
fields: [
{
name: 'heading',
label: 'Heading',
type: 'text',
required: true,
defaultValue: 'Core Features',
},
{
name: 'subheading',
label: 'Subheading',
type: 'text',
required: false,
defaultValue: 'Features',
},
{
name: 'features',
label: 'Features',
type: 'array',
minRows: 1,
maxRows: 12,
required: true,
fields: [
{
name: 'icon',
label: 'Icon',
type: 'select',
required: true,
options: [...availableIcons],
},
{
name: 'title',
label: 'Title',
type: 'text',
required: true,
},
{
name: 'description',
label: 'Description',
type: 'textarea',
required: true,
},
],
},
],
}
//src/components/Icons/index.tsx
import * as Icons from 'lucide-react'
export const iconMap = {
Timer: Icons.Timer,
Zap: Icons.Zap,
ZoomIn: Icons.ZoomIn,
PersonStanding: Icons.PersonStanding,
DollarSign: Icons.DollarSign,
MessagesSquare: Icons.MessagesSquare,
Blocks: Icons.Blocks,
Bot: Icons.Bot,
Film: Icons.Film,
MessageCircle: Icons.MessageCircle,
Settings2: Icons.Settings2,
// Add more icons here
}
export type IconName = keyof typeof iconMap
export const availableIcons = Object.keys(iconMap).map((key) => ({
label: key.replace(/([A-Z])/g, ' $1').trim(),
value: key as IconName,
}))
export function RenderIcon({ name, className }: { name: IconName; className?: string }) {
const Icon = iconMap[name]
return Icon ? <Icon className={className} /> : null
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment