Icon System
Relevant source files
The following files were used as context for generating this wiki page:The Grapevine website employs a hybrid icon system that combines a comprehensive third-party icon library with custom-built SVG icons for specific branding needs. The core of this system is the lucide-react library, which provides a wide range of general-purpose icons. These are loaded dynamically via a custom <Icon /> wrapper component to optimize performance. For brand-specific graphics, such as social media logos, the project uses dedicated React components that render inline SVGs.
This dual approach provides developers with the flexibility of a large, standardized icon set while maintaining control over critical brand assets. The system is designed to be easy to use, with clear conventions for both dynamic and custom icon implementation.
Sources: README.md:11, README.md:41-43, components/footer.tsx:5, components/footer.tsx:7, package.json:15
Core Technologies
The icon system is built upon two main technologies:
- Lucide React: A library of simply designed, consistent icons. It is listed as a dependency in the project's
package.json. - Custom SVG Components: Standard React functional components that return
<svg>elements for brand-specific icons.
Sources: README.md:11, package.json:15, components/icons/x.tsx
Icon Implementation Strategy
The project uses a clear strategy for deciding which type of icon to use. This diagram illustrates the developer's decision-making process.
This flow ensures that the lucide-react library is used for consistency in UI elements, while custom components are reserved for unique brand assets.
Sources: README.md:41-43, components/footer.tsx:150-165
Dynamic Icon Loading: The <Icon /> Component
The primary method for displaying icons is through the <Icon /> component. This component acts as a wrapper that dynamically imports and renders icons from the lucide-react library based on a name prop. This approach leverages React.lazy for code-splitting, meaning that icons are only loaded when they are needed, which can improve initial page load performance.
Sources: README.md:41-43, components/icon.tsx
Component Logic
The <Icon /> component follows a straightforward rendering logic. It takes an icon name and other styling props, dynamically imports the corresponding icon component from lucide-react/dynamic, and renders it within a React.Suspense boundary, which can show a fallback UI while the icon is loading.
This diagram shows the data flow for rendering a dynamic icon.
Sources: components/icon.tsx:4-18
Properties
The <Icon /> component accepts several props to customize its appearance, as detailed in the project's README.md.
| Prop | Type | Description | Default |
|---|---|---|---|
name | IconName | The kebab-case name of the icon from the Lucide library. (Required) | N/A |
size | number | The width and height of the icon in pixels. | undefined |
className | string | Custom CSS classes to apply to the icon. | undefined |
strokeWidth | number | The stroke width of the icon's lines. | 2 |
Sources: README.md:58-64, components/icon.tsx:6-11
Usage Example
To use a dynamic icon, import the <Icon /> component and provide the name of the desired icon from the Lucide library.
import Icon from "@/components/icon";
// Basic usage
<Icon name="check" />
// With size and custom class
<Icon name="arrow-right" size={24} className="text-primary" />
// With all props
<Icon name="user" size={20} className="text-navy" strokeWidth={2} />
Source: README.md:46-56
This pattern is used extensively throughout the application, for example on the product page to represent different layers of the platform.
Sources: app/product/page.tsx:52-85
Custom SVG Icons
For icons that are not part of the lucide-react library, such as social media logos, the project uses custom React components. These are typically simple, stateless functional components that return an <svg> element with hardcoded paths.
Sources: README.md:37, components/icons/x.tsx, components/icons/linkedin.tsx
Structure
A custom icon component is a self-contained file that exports a React component. It accepts standard props like width, height, and className to allow for basic customization.
Here is the implementation of the X (formerly Twitter) icon:
// components/icons/x.tsx
export default function XIcon({ width = 24, height = 24, className = "" }) {
return (
<svg
width={width}
height={height}
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
>
<path
d="M18.901 1.15344C17.821 1.61344 16.661 1.93344 15.441 2.09344C16.681 1.33344 17.641 0.193441 18.091 -1.14656C16.931 -0.426562 15.681 -0.0665625 14.361 0.173438C13.2934 -0.944135 11.8985 -1.58336 10.3828 -1.6542C8.86713 -1.72503 7.39891 -1.22436 6.221 -0.246562C5.0431 -0.731438 3.661 -0.246562 2.501 -1.14656C2.501 -1.14656 2.501 2.85344 2.501 5.85344C2.501 9.85344 5.501 12.8534 9.501 12.8534C9.501 12.8534 9.501 13.8534 9.501 14.8534C9.501 16.8534 8.501 17.8534 7.501 17.8534C7.501 17.8534 7.501 18.8534 7.501 19.8534C7.501 21.8534 9.501 22.8534 11.501 22.8534C16.501 22.8534 21.501 17.8534 21.501 10.8534C21.501 10.3534 21.501 9.85344 21.481 9.37344C22.503 8.67568 23.3353 7.7596 23.901 6.69344C22.941 7.11344 21.901 7.39344 20.821 7.49344C21.941 6.81344 22.781 5.69344 23.191 4.37344C22.231 4.91344 21.171 5.31344 20.041 5.51344C19.269 -0.426562 18.901 1.15344 18.901 1.15344Z"
fill="currentColor"
/>
</svg>
);
}
Source: components/icons/x.tsx:1-18
Usage Example
Unlike the dynamic <Icon /> component, custom icons are imported directly and used like any other React component. This is shown in the site's footer for social media links.
// components/footer.tsx
import XIcon from "./icons/x";
import LinkedInIcon from "./icons/linkedin";
// ...
<a
href="https://www.linkedin.com/company/grapevinetravel"
// ...
>
<LinkedInIcon width={20} height={20} />
</a>
<a
href="https://x.com/grapevine_trvl"
// ...
>
<XIcon width={20} height={20} />
</a>
Source: components/footer.tsx:5, components/footer.tsx:7, components/footer.tsx:150-165