GfG Design System Reference

Gifts for Good Design System

Last updated: March 17, 2026

Getting Started

Welcome to the GfG Design System. This is the single source of truth for all design decisions across the Gifts for Good Dashboard.

Overview

The GfG Design System provides a comprehensive set of colors, typography, components, and patterns built on Material-UI (MUI v6). It ensures consistency across the dashboard and streamlines development by providing pre-built, battle-tested components.

All colors are defined as CSS custom properties and MUI palette values. Typography uses Crimson Text for headings and Lato for body text. Components are fully customizable through the theme file.

Font Imports

Add this to your HTML head or import in your CSS:

<link href="https://fonts.googleapis.com/css2?family=Crimson+Text:wght@400&family=Lato:wght@400;700&display=swap" rel="stylesheet">

Theme Provider Setup

Wrap your application with ThemeProvider:

import { ThemeProvider } from '@mui/material/styles';
import gfgTheme from './theme/gfgTheme';

function App() {
  return (
    <ThemeProvider theme={gfgTheme}>
      {/* Your application */}
    </ThemeProvider>
  );
}

Component Details

Click any swatch to copy the hex code. All colors are available as CSS custom properties and MUI palette values.

Primary Brand Colors (Dust Family)

Dark Dust
#AF9577
--color-dark-dust
palette.primary.main
Rodeo Dust
#C8B298
--color-rodeo-dust
palette.primary.light
Light Dust
#F4EFEA
--color-light-dust
palette.primary.lighter
Clear Dust
#FBF9F7
--color-clear-dust
palette.primary.lightest

Neutrals

Rodeo Black
#333333
--color-rodeo-black
palette.text.primary
Graphite
#6D6D6D
--color-graphite
palette.text.secondary
Smoke
#E0E0E0
--color-smoke
palette.divider
Wax
#F5F5F5
--color-wax
palette.grey[100]
White
#FFFFFF
--color-white
palette.background.paper
Background
#FAFAFA
--color-background
palette.background.default

Semantic / Status Colors

Good Sage (Success)

Sage 1
#637058
--color-good-sage
Sage 2
#8C9583
--color-good-sage-2
Sage 3
#B5BBAF
--color-good-sage-3
Sage 4
#E0E3DD
--color-good-sage-4
Sage 5
#F5F6F4
--color-good-sage-5

Good Wine (Error)

Wine 1
#A34740
--color-good-wine
Wine 2
#BB7570
--color-good-wine-2
Wine 3
#D4A4A1
--color-good-wine-3
Wine 4
#EED4D3
--color-good-wine-4
Wine 5
#F9F1F0
--color-good-wine-bg

Good Ochre (Warning)

Ochre 1
#8A5D1F
--color-good-ochre
Ochre 2
#AC8958
--color-good-ochre-2
Ochre 3
#CFB591
--color-good-ochre-3
Ochre 4
#F3E3CD
--color-good-ochre-4
Ochre 5
#FBF6EF
--color-good-ochre-bg

Good Night (Info)

Night 1
#2B4A60
--color-good-night
Night 2
#5E798C
--color-good-night-2
Night 3
#91A8B8
--color-good-night-3
Night 4
#C7D9E6
--color-good-night-4
Night 5
#F1F5F9
--color-good-night-bg

Component Details

Typography is built on Crimson Text for headings (elegant, serif) and Lato for body text and UI (clean, sans-serif).

Font Families

Crimson Text (400) for headings • Lato (400, 700) for body/UI

Typography Variants

Heading 1 (h1)
Page Titles and Hero Text
Crimson Text • 30px • Weight 400 • Line-height 1.2
Heading 2 (h2)
Major Section Headings
Crimson Text • 24px • Weight 400 • Line-height 1.2
Heading 3 (h3)
Section Titles
Crimson Text • 20px • Weight 400 • Line-height 1.2
Heading 4 (h4)
Card Titles
Crimson Text • 18px • Weight 400 • Line-height 1.2
Subtitle 1
Card Title Alternative
Lato • 18px • Weight 600 • Line-height 1.5
Body 1
This is default body text. Use this for primary paragraphs and content.
Lato • 14px • Weight 400 • Line-height 1.5
Body 2
This is secondary body text for supporting information.
Lato • 13px • Weight 400 • Line-height 1.5
Caption
Small text for timestamps, descriptions, and metadata
Lato • 12px • Weight 400 • Line-height 1.4
Overline
Section Labels & Dividers
Lato • 11px • Weight 700 • Uppercase • Letter-spacing 2px
Stat Value
42,500
Crimson Text • 42px • Weight 400 • Line-height 1

Usage Guidelines

Use Crimson Text (serif) for headings to create visual hierarchy and elegance. Use Lato (sans-serif) for body text and UI controls for clarity and readability. Never mix serif and sans-serif within a single line or element.

Component Details

CSS custom properties available for use throughout your application. All tokens are defined in the :root selector.

Complete Token Reference

:root {
  /* Brand Colors - Dust Family */
  --color-dark-dust: #AF9577;
  --color-rodeo-dust: #C8B298;
  --color-light-dust: #F4EFEA;
  --color-clear-dust: #FBF9F7;

  /* Neutrals */
  --color-rodeo-black: #333333;
  --color-graphite: #6D6D6D;
  --color-smoke: #E0E0E0;
  --color-wax: #F5F5F5;
  --color-white: #FFFFFF;
  --color-card-border: #F0ECE8;
  --color-background: #FAFAFA;

  /* Semantic Colors */
  --color-good-sage: #637058;
  --color-good-sage-2: #8C9583;
  --color-good-sage-3: #B5BBAF;
  --color-good-sage-4: #E0E3DD;
  --color-good-sage-5: #F5F6F4;
  --color-good-wine: #A34740;
  --color-good-wine-2: #BB7570;
  --color-good-wine-3: #D4A4A1;
  --color-good-wine-4: #EED4D3;
  --color-good-wine-bg: #F9F1F0;
  --color-good-ochre: #8A5D1F;
  --color-good-ochre-2: #AC8958;
  --color-good-ochre-3: #CFB591;
  --color-good-ochre-4: #F3E3CD;
  --color-good-ochre-bg: #FBF6EF;
  --color-good-night: #2B4A60;
  --color-good-night-2: #5E798C;
  --color-good-night-3: #91A8B8;
  --color-good-night-4: #C7D9E6;
  --color-good-night-bg: #F1F5F9;

  /* Typography */
  --font-lato: "Lato", sans-serif;
  --font-crimson: "Crimson Text", Georgia, serif;

  /* Spacing & Sizing */
  --sidebar-width: 240px;
  --topbar-height: 76px;
  --radius-card: 10px;
  --radius-pill: 20px;
  --radius-btn: 6px;
  --radius-sm: 4px;
  --grid-gap: 20px;
}

How to Use Tokens

In CSS, reference tokens using the var() function:

.my-element {
  color: var(--color-dark-dust);
  background-color: var(--color-clear-dust);
  border-radius: var(--radius-card);
  font-family: var(--font-crimson);
  padding: var(--grid-gap);
}

In JavaScript, access tokens from computed styles:

const color = getComputedStyle(document.documentElement)
  .getPropertyValue('--color-dark-dust')
  .trim(); // Returns: #AF9577

Component Details

Four border radius values create visual consistency across components.

Radius Scale

Card Radius (10px)
border-radius: 10px (--radius-card)
Pill Radius (20px)
border-radius: 20px (--radius-pill)
Button Radius (6px)
border-radius: 6px (--radius-btn)
Small Radius (4px)
border-radius: 4px (--radius-sm)

Usage by Component

Component Radius Value CSS Variable
Cards, Containers 10px var(--radius-card)
Pills, Chips, Badges 20px var(--radius-pill)
Buttons, Inputs 8px var(--radius-btn)
Small UI Elements 4px var(--radius-sm)

Component Details

Cards are fundamental containers for content. All cards use 10px border radius, 1px border with smoke color, and 20px padding.

Default Card

Basic Card
Campaign Overview
Last updated 2 hours ago

This is a typical card component with a title, subtitle, and content area. Cards are used to group related information and create visual separation.

.card {
  background-color: var(--color-white);
  border-radius: var(--radius-card);
  border: 1px solid var(--color-smoke);
  padding: 20px;
  transition: box-shadow 0.2s ease;
}

.card:hover {
  box-shadow: 0 4px 16px rgba(51, 51, 51, 0.06);
}

Stat Card

Metric Display Pattern
Total Donations
24,850
↑ 12% from last month
function StatCard({ label, value, subtitle }) {
  return (
    <div className="stat-card">
      <div className="stat-card-overline">{label}</div>
      <div className="stat-card-value">{value}</div>
      <div className="stat-card-subtitle">{subtitle}</div>
    </div>
  );
}
White Variant — For #fafafa / Clear Dust Backgrounds

Use stat-card--white when stat cards sit on a page with a #fafafa (clear dust) background. The pure white card surface creates the necessary contrast separation.

Total Donations
24,850
↑ 12% from last month
Active Campaigns
12
3 pending approval
Total Gifted
$184K
↑ 28% YoY
Avg Rating
4.8
From 542 recipients
{/* White variant — use on #fafafa / clear-dust page backgrounds */}
function StatCard({ label, value, subtitle, variant = 'default' }) {
  return (
    <div className={`stat-card ${variant === 'white' ? 'stat-card--white' : ''}`}>
      <div className="stat-card-overline">{label}</div>
      <div className="stat-card-value">{value}</div>
      <div className="stat-card-subtitle">{subtitle}</div>
    </div>
  );
}

// Usage on a #fafafa background page:
<StatCard variant="white" label="Total Donations" value="24,850" subtitle="↑ 12% from last month" />

Campaign Card

Content Card with Metadata
Holiday Gift Drive 2026
Ends Dec 25, 2026 • 1,243 supporters

Help us deliver gifts to families in need this holiday season.

72%

Metric Card Grid

Multiple Metric Cards
Active Campaigns
12
3 pending approval
Total Gifted
$184K
↑ 28% YoY
Fulfillment Rate
94%
↑ 3% from last quarter
Avg Rating
4.8
From 542 recipients

Media Card

Image + Content Card

A card with a top image area and content below. Use for product tiles, blog previews, or any content that leads with a visual.

image
Artisan Gift Box
Curated collection of fair-trade goods supporting women artisans in Guatemala.
$85.00 In Stock
eco
Ocean Cleanup Bracelet
Each bracelet removes 5 lbs of trash from the ocean. Recycled materials.
$28.00 Low Stock
local_cafe
Fair Trade Coffee Set
Organic coffee sourced from smallholder farms in Colombia and Ethiopia.
$42.00 In Stock
/* Media card — image top, content below */
.media-card {
  background: var(--color-white);
  border: 1px solid var(--color-smoke);
  border-radius: var(--radius-card);
  overflow: hidden;
  transition: box-shadow 0.2s ease;
}

.media-card:hover {
  box-shadow: 0 4px 16px rgba(51, 51, 51, 0.06);
}

.media-card__image {
  height: 160px;
  background: var(--color-light-dust);
  display: flex;
  align-items: center;
  justify-content: center;
}

.media-card__image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.media-card__body {
  padding: 16px 20px;
}

.media-card__title {
  font-family: var(--font-crimson);
  font-size: 18px;
  font-weight: 400;
  color: var(--color-rodeo-black);
  margin-bottom: 8px;
}

.media-card__subtitle {
  font-size: 13px;
  color: var(--color-graphite);
  margin-bottom: 12px;
}

.media-card__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

Campaign Card with Separator

Split Layout — Body + Status Panel

The primary card pattern in the campaigns list. A horizontal row with an image area, body content, and a right-side status panel separated by a 1px border. The card uses --color-card-border (#F0ECE8) and gains a subtle shadow on hover.

card_giftcard
Earth Day Celebration
$200 Collection
Gift for Good sends 15 recipients
Budget
$3,000
Active
notifications
bar_chart
more_vert
Started Apr 22, 2026
71 days left
51% redeemed
/* Campaign card — split layout with separator */
.campaign-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--color-smoke);
  border-radius: var(--radius-card);
  background: var(--color-white);
  overflow: hidden;
  transition: box-shadow 0.2s ease;
}

.campaign-card:hover {
  box-shadow: 0 4px 16px rgba(51, 51, 51, 0.06);
}

.campaign-card__row {
  display: flex;
  align-items: stretch;
}

/* Left image area */
.campaign-card__image {
  width: 140px;
  min-height: 140px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

/* Center body */
.campaign-card__body {
  flex: 1;
  padding: 18px 20px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* Right status panel — border-left is the separator */
.campaign-card__right {
  width: 320px;
  flex-shrink: 0;
  padding: 18px 20px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  border-left: 1px solid var(--color-card-border);
}

/* Card border token */
/* --color-card-border: #F0ECE8 (warm-tinted) */

/* Action icon buttons inside cards */
.card-action-btn {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--color-smoke);
  border-radius: var(--radius-sm);
  background: none;
  color: var(--color-graphite);
  cursor: pointer;
  transition: border-color 0.15s;
}

.card-action-btn:hover {
  border-color: var(--color-dark-dust);
  color: var(--color-dark-dust);
}

/* Meta dot separator */
.meta-dot {
  width: 3px;
  height: 3px;
  background: var(--color-rodeo-dust);
  border-radius: 50%;
}

Component Details

Buttons use 6px border radius, 600 font weight in Lato, and come in multiple variants for different contexts. All buttons include a Material-style ink ripple on click, tinted to brand colors.

Interaction: Click Ripple

All buttons use a JS-driven ink ripple identical to MUI's TouchRipple. The ripple originates from the click point, expands to fill the button, then fades on release. Contained buttons (dark surfaces) use a white 35% ripple. Outlined and text buttons use a Dark Dust 30% ripple. Click and hold any button below to see it.

Try the ripple — click each variant

Contained Buttons

Primary (Dark Dust)
Dark CTA (Rodeo Black)
button.btn-contained {
  background-color: var(--color-dark-dust);
  color: var(--color-white);
  padding: 10px 20px;
  border-radius: var(--radius-btn);
  font-family: var(--font-lato);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 2px;
  border: none;
  cursor: pointer;
}

button.btn-contained:hover {
  background-color: #9B7D63;
  transform: translateY(-1px);
}

Outlined Buttons

Secondary Actions
button.btn-outlined {
  background-color: transparent;
  border: 1px solid var(--color-dark-dust);
  color: var(--color-dark-dust);
  padding: 10px 20px;
  border-radius: var(--radius-btn);
  font-family: var(--font-lato);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 2px;
  cursor: pointer;
}

Text Buttons

Tertiary / Link Buttons
button.btn-text {
  background-color: transparent;
  color: var(--color-dark-dust);
  padding: 10px 20px;
  border: 1px solid transparent;
  border-radius: var(--radius-btn);
  font-family: var(--font-lato);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 2px;
  cursor: pointer;
}

button.btn-text:hover {
  background-color: rgba(175, 149, 119, 0.05);
  border-color: var(--color-dark-dust);
}

Icon Buttons

Card Action Icons

Small 32×32 icon buttons used inside cards for contextual actions. Default state has a light border; hover transitions to Dark Dust.

Notifications · Analytics · Download · Edit · More
Active State

When an icon button is toggled on (e.g. analytics drawer open), apply the active state with Dark Dust border and color.

Active / toggled-on state
/* Icon button — default */
.icon-btn {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--color-smoke);
  border-radius: var(--radius-sm);
  background: none;
  color: var(--color-graphite);
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s;
  padding: 0;
}

/* Icon button — hover */
.icon-btn:hover {
  border-color: var(--color-dark-dust);
  color: var(--color-dark-dust);
}

/* Icon button — active / toggled-on */
.icon-btn--active {
  border-color: var(--color-dark-dust);
  color: var(--color-dark-dust);
}

/* SVG icon sizing inside buttons */
.icon-btn svg {
  width: 14px;
  height: 14px;
}

Button Best Practices

Usage Tips
Use contained buttons for primary actions (Create, Save, Submit). Use outlined buttons for secondary actions (Cancel, Learn More). Use text buttons for tertiary actions (View, Edit, Delete). Always provide clear, action-oriented labels.

Component Details

Eight distinct status pill styles for campaign states and order statuses. Use 20px border radius and 600 font weight.

All Status States

Complete Status Set

Each status indicates a specific state. Use consistently across your application.

Active Fulfilled Pending Processing Cancelled Draft Closed Archived

Status Definitions

Status Color Background Use Case
Active #637058 #E0E3DD Campaign is live and accepting gifts
Fulfilled #637058 #E0E3DD Gift delivery completed successfully
Pending #8A5D1F #F3E3CD Awaiting action or approval
Processing #2B4A60 #C7D9E6 In progress, e.g., sending, packaging
Cancelled #A34740 #EED4D3 Campaign cancelled or gift declined
Draft #6D6D6D #F4EFEA Unsaved or incomplete campaign
Closed #6D6D6D #F4EFEA Campaign ended, no longer accepting gifts
Archived #FFFFFF #333333 Historical campaign, not active

CSS Styles

.chip {
  display: inline-block;
  padding: 6px 12px;
  border-radius: var(--radius-pill);
  font-family: var(--font-lato);
  font-size: 12px;
  font-weight: 600;
}

.chip-active { background-color: #E0E3DD; color: #637058; }
.chip-fulfilled { background-color: #E0E3DD; color: #637058; }
.chip-pending { background-color: #F3E3CD; color: #8A5D1F; }
.chip-processing { background-color: #C7D9E6; color: #2B4A60; }
.chip-cancelled { background-color: #EED4D3; color: #A34740; }
.chip-draft { background-color: #F4EFEA; color: #6D6D6D; }
.chip-closed { background-color: #F4EFEA; color: #6D6D6D; }
.chip-archived { background-color: #333333; color: #FFFFFF; }

Alert Button

Alert Action Button with Badge

Used on campaign cards when there are delivery failures or issues requiring attention. The button is filled Good Wine with a count badge.

3
1
Alert buttons with count badges
/* Alert action button — filled Good Wine */
.action-btn--alert {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-good-wine);
  border: 1px solid var(--color-good-wine);
  border-radius: var(--radius-sm);
  color: var(--color-white);
  cursor: pointer;
  position: relative;
}

.action-btn--alert:hover {
  background: #8B2E28;
  border-color: #8B2E28;
}

/* Count badge — positioned top-right of button */
.action-badge {
  position: absolute;
  top: -5px;
  right: -5px;
  width: 16px;
  height: 16px;
  background: var(--color-good-wine-bg);
  color: var(--color-good-wine);
  border: 1px solid var(--color-good-wine);
  border-radius: 50%;
  font-family: var(--font-lato);
  font-size: 10px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}

Notification Badge

Nav / Sidebar Notification Badges

Used in navigation items to indicate unread counts. Dark Dust background with white text, fully rounded pill.

2 5 8 ! Default (Dark Dust) & Urgent (Good Wine)
/* Notification badge — nav items, sidebar counts */
.badge {
  background: var(--color-dark-dust);
  color: var(--color-white);
  font-family: var(--font-lato);
  font-size: 12px;
  font-weight: 700;
  border-radius: 999px;
  width: 22px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Urgent variant */
.badge--urgent {
  background: var(--color-good-wine);
}

Alert & Notification Dialogs

Tinted Dialog Boxes

Full-width tinted boxes for contextual alerts, confirmations, warnings, and informational messages. Each uses the Level 5 background tint, a 3px left accent border in the main semantic color, and Level 1 text color for the title.

check_circle Success

Your campaign has been published and gifts are now being delivered to all 24 recipients.

error Error

3 gift deliveries failed due to invalid email addresses. Please review the recipient list and retry.

warning Warning

Your campaign budget is 90% spent with 15 days remaining. Consider adding funds or closing the campaign early.

info Info

Your Earth Day campaign is scheduled to launch on April 22. Recipients will receive invitations at 9:00 AM ET.

/* Base alert dialog */
.alert-dialog {
  border-radius: var(--radius-btn);
  padding: 16px 20px;
  border-left: 3px solid;
}

.alert-dialog__header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
}

.alert-dialog__title {
  font-family: var(--font-lato);
  font-size: 13px;
  font-weight: 700;
}

.alert-dialog__body {
  font-family: var(--font-lato);
  font-size: 13px;
  color: var(--color-graphite);
  line-height: 1.5;
}

/* Success */
.alert-dialog--success {
  background: var(--color-good-sage-5);
  border-left-color: var(--color-good-sage);
}
.alert-dialog--success .alert-dialog__title,
.alert-dialog--success .material-icons-outlined {
  color: var(--color-good-sage);
}

/* Error */
.alert-dialog--error {
  background: var(--color-good-wine-bg);
  border-left-color: var(--color-good-wine);
}
.alert-dialog--error .alert-dialog__title,
.alert-dialog--error .material-icons-outlined {
  color: var(--color-good-wine);
}

/* Warning */
.alert-dialog--warning {
  background: var(--color-good-ochre-bg);
  border-left-color: var(--color-good-ochre);
}
.alert-dialog--warning .alert-dialog__title,
.alert-dialog--warning .material-icons-outlined {
  color: var(--color-good-ochre);
}

/* Info */
.alert-dialog--info {
  background: var(--color-good-night-bg);
  border-left-color: var(--color-good-night);
}
.alert-dialog--info .alert-dialog__title,
.alert-dialog--info .material-icons-outlined {
  color: var(--color-good-night);
}

Component Details

Input fields, search bars, and dropdowns with GfG styling.

Text Input

Outlined Text Field with Floating Label

Follows MUI's outlined input pattern. The label sits inside the field at rest, then floats into the top-left border notch on focus or when filled.

<!-- HTML -->
<div class="mui-text-field">
  <input type="text" id="myField" class="mui-text-field__input" placeholder=" ">
  <label for="myField" class="mui-text-field__label">Campaign Name</label>
</div>
/* Outlined text field with floating label */
.mui-text-field {
  position: relative;
}

.mui-text-field__input {
  width: 100%;
  padding: 14px 14px;
  border: 1px solid var(--color-smoke);
  border-radius: var(--radius-btn);
  font-family: var(--font-lato);
  font-size: 14px;
  color: var(--color-rodeo-black);
  background: var(--color-white);
  transition: border-color 0.15s;
}

.mui-text-field__label {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--font-lato);
  font-size: 14px;
  color: var(--color-graphite);
  background: var(--color-white);
  padding: 0 4px;
  pointer-events: none;
  transition: all 0.15s ease;
}

/* Float the label on focus or when filled */
.mui-text-field__input:focus + .mui-text-field__label,
.mui-text-field__input:not(:placeholder-shown) + .mui-text-field__label {
  top: 0;
  transform: translateY(-50%);
  font-size: 11px;
  color: var(--color-dark-dust);
}

.mui-text-field__input:focus {
  outline: none;
  border-color: var(--color-dark-dust);
}

/* MUI Theme Override */
MuiOutlinedInput: {
  styleOverrides: {
    root: {
      borderRadius: '6px',
      fontFamily: '"Lato", sans-serif',
      '&:hover .MuiOutlinedInput-notchedOutline': {
        borderColor: '#AF9577',
      },
      '&.Mui-focused .MuiOutlinedInput-notchedOutline': {
        borderColor: '#AF9577',
        borderWidth: '1px',
      },
    },
  },
},
MuiInputLabel: {
  styleOverrides: {
    root: {
      fontFamily: '"Lato", sans-serif',
      color: '#6D6D6D',
      '&.Mui-focused': {
        color: '#AF9577',
      },
    },
  },
}

Search Input

Search with Icon
search

Select Dropdown

Mirrors MUI's <Select> with outlined variant — floating label, helper text, and error state. The label floats into the top border notch on focus or when a value is selected.

Labels & Helper Text
Filter by campaign status
Reporting period
Required — please select a cause
<!-- Outlined select with floating label + helper text -->
<div class="mui-select">
  <div class="mui-select__field">
    <select id="mySelect" class="mui-select__native">
      <option value=""></option>
      <option value="active">Active</option>
      <option value="pending">Pending</option>
    </select>
    <label for="mySelect" class="mui-select__label">Status</label>
  </div>
  <div class="mui-select__helper">Filter by campaign status</div>
</div>

<!-- Error variant -->
<div class="mui-select mui-select--error">
  <div class="mui-select__field">
    <select id="cause" class="mui-select__native">
      <option value=""></option>
      <option value="sage">Good Sage</option>
    </select>
    <label for="cause" class="mui-select__label">Cause Area</label>
  </div>
  <div class="mui-select__helper mui-select__helper--error">Required</div>
</div>
/* Outlined Select — mirrors MUI <Select variant="outlined"> */
.mui-select__field { position: relative; }

.mui-select__native {
  width: 100%;
  padding: 14px 44px 14px 14px;
  border: 1px solid var(--color-smoke);
  border-radius: var(--radius-btn);
  font-family: var(--font-lato);
  font-size: 14px;
  color: var(--color-rodeo-black);
  background-color: var(--color-white);
  cursor: pointer;
  appearance: none;
  background-image: url("..chevron-svg..");
  background-repeat: no-repeat;
  background-position: right 14px center;
  transition: border-color 250ms cubic-bezier(0.4,0,0.2,1);
}

.mui-select__label {
  position: absolute;
  left: 12px; top: 50%;
  transform: translateY(-50%);
  font-size: 14px;
  color: var(--color-graphite);
  background: var(--color-white);
  padding: 0 4px;
  pointer-events: none;
  transition: top 250ms cubic-bezier(0.4,0,0.2,1),
              font-size 250ms cubic-bezier(0.4,0,0.2,1),
              color 250ms cubic-bezier(0.4,0,0.2,1);
}

/* Float into notch on focus or filled */
.mui-select__native:focus + .mui-select__label,
.mui-select--filled .mui-select__label {
  top: 0; font-size: 11px;
  color: var(--color-dark-dust);
}

.mui-select__native:focus {
  border-color: var(--color-dark-dust);
}

/* Helper text */
.mui-select__helper {
  font-size: 12px;
  color: var(--color-graphite);
  margin-top: 4px;
  padding-left: 14px;
}

/* Error state */
.mui-select--error .mui-select__native { border-color: var(--color-good-wine); }
.mui-select--error .mui-select__label  { color: var(--color-good-wine); }
.mui-select__helper--error { color: var(--color-good-wine); }
// MUI Theme Override
MuiSelect: {
  defaultProps: { variant: 'outlined' },
  styleOverrides: {
    root: {
      fontFamily: '"Lato", sans-serif',
      fontSize: '14px',
    },
    icon: { color: '#6D6D6D' },
  },
},
MuiFormHelperText: {
  styleOverrides: {
    root: {
      fontFamily: '"Lato", sans-serif',
      fontSize: '12px',
      marginLeft: '14px',
      marginTop: '4px',
    },
  },
},

Component Details

Progress bars and metric display patterns.

Progress Bar

Standard Progress Bar

Campaign Goal: 25 Gifts

17 / 25

Donor Participation: 85%

85%
.progress-bar {
  height: 4px;
  background-color: var(--color-smoke);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  background-color: var(--color-dark-dust);
  border-radius: var(--radius-sm);
  transition: width 0.3s ease;
}

Metric Drawer Pattern

A collapsible metrics section with a grid of metric cards. Ideal for dashboard overviews.

4-Column Metric Grid
Total Campaigns
48
All time
Gifts Sent
3.2K
↑ 18% YoY
Amount Raised
$542K
↑ 34% YoY
Avg Fulfillment
94%
↑ 2% from Q3

Component Details

Grid system and spacing guidelines for consistent layouts.

Grid System

Standard grid gap is 20px (defined as --grid-gap). Use CSS Grid for flexible layouts.

4-Column Grid (Auto-fill)
Column 1
Column 2
Column 3
Column 4
Column 5
Column 6
.grid-container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--grid-gap);
}

Spacing Scale

MUI uses an 8px base unit. Standard spacing value is var(--grid-gap) = 20px.

Size Pixels Use Case
xs 4px Small gaps within components
sm 8px Small spacing, icon gaps
md 16px Card padding, moderate spacing
lg 20px Standard grid gap, section spacing
xl 30px Major section gaps, page padding
2xl 40px Large section separation

Responsive Breakpoints

Breakpoint Width Device
xs 0px - 600px Mobile phones
sm 600px - 960px Small tablets
md 960px - 1264px Tablets & small desktops
lg 1264px - 1904px Desktop computers
xl 1904px+ Large displays

Component Details

Material Icons Outlined from Google Fonts. Use 24px as the standard size.

Common Icons

home
home
dashboard
dashboard
campaigns
campaigns
people
people
analytics
analytics
settings
settings
edit
edit
delete
delete
add
add
close
close
search
search
more_vert
more_vert

Icon Usage

<span class="material-icons-outlined">campaign</span>

<!-- Sizes -->
<span class="material-icons-outlined" style="font-size: 18px;">home</span>
<span class="material-icons-outlined" style="font-size: 24px;">home</span>
<span class="material-icons-outlined" style="font-size: 32px;">home</span>

<!-- Colors -->
<span class="material-icons-outlined" style="color: var(--color-dark-dust);">home</span>

Component Details

Complete Material-UI v6 theme configuration. Copy this file to your project.

gfgTheme.ts

Save this as src/theme/gfgTheme.ts in your React project.

import { createTheme } from '@mui/material/styles';

const gfgTheme = createTheme({
  palette: {
    primary: {
      main: '#AF9577', // Dark Dust
      light: '#C8B298', // Rodeo Dust
      lighter: '#F4EFEA', // Light Dust
      lightest: '#FBF9F7', // Clear Dust
    },
    secondary: {
      main: '#6D6D6D', // Graphite
    },
    text: {
      primary: '#333333', // Rodeo Black
      secondary: '#6D6D6D', // Graphite
    },
    background: {
      default: '#FAFAFA',
      paper: '#FFFFFF',
    },
    divider: '#E0E0E0', // Smoke
    success: {
      main: '#637058', // Good Sage
      light: '#E0E3DD', // Good Sage 4
    },
    error: {
      main: '#A34740', // Good Wine — NOT MUI default #d32f2f
      light: '#EED4D3', // Good Wine 4
    },
    warning: {
      main: '#8A5D1F', // Good Ochre
      light: '#F3E3CD', // Good Ochre 4
    },
    info: {
      main: '#2B4A60', // Good Night
      light: '#C7D9E6', // Good Night 4
    },
    grey: {
      100: '#F5F5F5', // Wax
    },
  },
  typography: {
    fontFamily: '"Lato", sans-serif',
    h1: {
      fontFamily: '"Crimson Text", Georgia, serif',
      fontSize: '30px',
      fontWeight: 400,
      lineHeight: 1.2,
    },
    h2: {
      fontFamily: '"Crimson Text", Georgia, serif',
      fontSize: '24px',
      fontWeight: 400,
      lineHeight: 1.2,
    },
    h3: {
      fontFamily: '"Crimson Text", Georgia, serif',
      fontSize: '20px',
      fontWeight: 400,
      lineHeight: 1.2,
    },
    h4: {
      fontFamily: '"Crimson Text", Georgia, serif',
      fontSize: '18px',
      fontWeight: 400,
      lineHeight: 1.2,
    },
    h5: {
      fontFamily: '"Lato", sans-serif',
      fontSize: '16px',
      fontWeight: 600,
    },
    subtitle1: {
      fontFamily: '"Lato", sans-serif',
      fontSize: '18px',
      fontWeight: 600,
    },
    body1: {
      fontFamily: '"Lato", sans-serif',
      fontSize: '14px',
      fontWeight: 400,
      lineHeight: 1.5,
      color: '#6D6D6D',
    },
    body2: {
      fontFamily: '"Lato", sans-serif',
      fontSize: '13px',
      fontWeight: 400,
      lineHeight: 1.5,
    },
    caption: {
      fontFamily: '"Lato", sans-serif',
      fontSize: '12px',
      fontWeight: 400,
    },
    overline: {
      fontFamily: '"Lato", sans-serif',
      fontSize: '11px',
      fontWeight: 700,
      color: '#AF9577', // Dark Dust
      textTransform: 'uppercase',
      letterSpacing: '2px',
    },
    // Custom variant — stat card numbers
    statValue: {
      fontFamily: '"Crimson Text", Georgia, serif',
      fontSize: '42px',
      fontWeight: 400,
      lineHeight: 1,
      color: '#333333', // Rodeo Black
    },
  },
  shape: {
    borderRadius: 10,
  },
  spacing: 8,
  mixins: {
    toolbar: {
      minHeight: 76,
    },
  },
  components: {
    MuiCard: {
      styleOverrides: {
        root: {
          borderRadius: '10px',
          border: '1px solid #E0E0E0',
          boxShadow: 'none',
        },
      },
    },
    MuiPaper: {
      styleOverrides: {
        rounded: { borderRadius: 10 },
      },
    },
    MuiCardContent: {
      styleOverrides: {
        root: {
          padding: '20px',
          '&:last-child': {
            paddingBottom: '20px',
          },
        },
      },
    },
    MuiButton: {
      defaultProps: {
        disableElevation: true,
        // Ripple is enabled by default in MUI — keep it on
      },
      styleOverrides: {
        root: {
          borderRadius: '6px',
          fontFamily: '"Lato", sans-serif',
          fontSize: '11px',
          fontWeight: 600,
          textTransform: 'uppercase',
          letterSpacing: '2px',
        },
        contained: {
          backgroundColor: '#AF9577',
          color: '#FFFFFF',
          boxShadow: 'none',
          '&:hover': {
            backgroundColor: '#9B7D63',
            boxShadow: 'none',
          },
        },
        outlined: {
          borderColor: '#AF9577',
          color: '#AF9577',
          '&:hover': {
            backgroundColor: 'rgba(175, 149, 119, 0.05)',
          },
        },
      },
    },
    // Brand-colored ripple across all components
    MuiTouchRipple: {
      styleOverrides: {
        rippleVisible: {
          animationDuration: '550ms',
        },
        child: {
          // Dark Dust at 30% — on-brand ink
          backgroundColor: 'rgba(175, 149, 119, 0.3)',
        },
        childLeaving: {
          animationDuration: '550ms',
        },
      },
    },
    MuiChip: {
      styleOverrides: {
        root: {
          borderRadius: '20px',
          fontWeight: 600,
          fontSize: '12px',
          fontFamily: '"Lato", sans-serif',
        },
      },
    },
    MuiAppBar: {
      styleOverrides: {
        root: {
          backgroundColor: '#FFFFFF',
          color: '#333333',
          boxShadow: 'none',
          borderBottom: '1px solid #E0E0E0',
        },
      },
    },
    MuiToolbar: {
      styleOverrides: {
        root: {
          minHeight: '76px',
        },
      },
    },
    MuiDrawer: {
      styleOverrides: {
        paper: {
          backgroundColor: '#FFFFFF',
          borderRight: '1px solid #E0E0E0',
          width: '240px',
        },
      },
    },
    MuiTextField: {
      styleOverrides: {
        root: {
          '& .MuiOutlinedInput-root': {
            borderRadius: '6px',
            '& fieldset': {
              borderColor: '#E0E0E0',
            },
            '&:hover fieldset': {
              borderColor: '#AF9577',
            },
            '&.Mui-focused fieldset': {
              borderColor: '#AF9577',
            },
          },
        },
      },
    },
  },
});

export default gfgTheme;

Component Details

Helper functions and utility objects for common patterns.

Status Pill Styles Utility

Use this utility to get styles for status pills. Returns color and backgroundColor.

export const statusPillStyles: Record<string, { color: string; backgroundColor: string }> = {
  active: { color: '#637058', backgroundColor: '#E0E3DD' },
  fulfilled: { color: '#637058', backgroundColor: '#E0E3DD' },
  pending: { color: '#8A5D1F', backgroundColor: '#F3E3CD' },
  processing: { color: '#2B4A60', backgroundColor: '#C7D9E6' },
  cancelled: { color: '#A34740', backgroundColor: '#EED4D3' },
  draft: { color: '#6D6D6D', backgroundColor: '#F4EFEA' },
  closed: { color: '#6D6D6D', backgroundColor: '#F4EFEA' },
  archived: { color: '#FFFFFF', backgroundColor: '#333333' },
};

// Usage
const status = 'active';
const styles = statusPillStyles[status];
// Returns: { color: '#637058', backgroundColor: '#E0E3DD' }

Color Utilities

// Get CSS variable value
export const getCSSVariable = (varName: string): string => {
  return getComputedStyle(document.documentElement)
    .getPropertyValue(varName)
    .trim();
};

// Format currency
export const formatCurrency = (value: number): string => {
  return new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency: 'USD',
    minimumFractionDigits: 0,
    maximumFractionDigits: 0,
  }).format(value);
};

// Format percentage
export const formatPercent = (value: number): string => {
  return `${Math.round(value)}%`;
};

// Get semantic color based on status
export const getStatusColor = (status: string): string => {
  const colorMap: Record<string, string> = {
    active: '#637058',
    fulfilled: '#637058',
    pending: '#8A5D1F',
    processing: '#2B4A60',
    cancelled: '#A34740',
    draft: '#6D6D6D',
    closed: '#6D6D6D',
    archived: '#333333',
  };
  return colorMap[status] || '#6D6D6D';
};

Component Helpers

// Get button variant based on context
export const getButtonVariant = (context: 'primary' | 'secondary' | 'tertiary') => {
  const variants = {
    primary: { variant: 'contained', color: 'primary' },
    secondary: { variant: 'outlined', color: 'primary' },
    tertiary: { variant: 'text', color: 'primary' },
  };
  return variants[context];
};

// Truncate long text with ellipsis
export const truncateText = (text: string, length: number): string => {
  return text.length > length ? text.substring(0, length) + '...' : text;
};

// Combine class names conditionally
export const classNames = (...classes: (string | boolean | undefined)[]): string => {
  return classes.filter(Boolean).join(' ');
};

Component Details

Track all design system updates and version history here.

Version History

March 16, 2026 — v1.0.0
Initial Release
- Complete color palette documentation
- Typography system with all variants
- CSS custom properties (design tokens)
- Border radius scale
- Card, button, and status pill components
- Navigation patterns
- Form controls
- Progress bars and metrics
- Layout patterns and grid system
- Complete MUI v6 theme file
- Utility functions and helpers
Future Updates
Additional components and patterns will be documented here as they are added to the design system.

How to Document Changes

Documentation Guide
When making updates to the design system, add a new changelog entry at the top with the date and version number. List all changes, new components, modifications, or removals. Be specific about what changed and why.

GfG Design System Reference • Last updated March 16, 2026 • v1.0.0

This is the single source of truth for design decisions across the Gifts for Good Dashboard.