Skip to main content

Overview

Mantlz SDK provides flexible theming capabilities that allow you to create fully custom themes or modify existing ones. You can customize every aspect of your forms using the appearance prop.

Theme Structure

A theme in Mantlz SDK is structured with three main sections:

Form

Container, title, and description styling

Field

Input fields, labels, and error messages

Button

Submit button styling and states

Theme Type Definition

Here’s the complete TypeScript interface for creating a custom theme:
export interface Theme {
  form: {
    container: CSSProperties;
    containerDark?: CSSProperties;
    title: CSSProperties;
    titleDark?: CSSProperties;
    description: CSSProperties;
    descriptionDark?: CSSProperties;
    background?: CSSProperties;
  };
  field: {
    container: CSSProperties;
    label: CSSProperties;
    labelDark?: CSSProperties;
    input: ExtendedCSSProperties;
    inputDark?: ExtendedCSSProperties;
    error: CSSProperties;
  };
  button: ExtendedCSSProperties;
  buttonDark?: ExtendedCSSProperties;
}

Using the Appearance Prop

The appearance prop allows you to customize forms without creating a full theme:
import { Mantlz } from '@mantlz/nextjs';

export default function CustomForm() {
  return (
    <Mantlz
      formId="your-form-id"
      appearance={{
        variables: {
          colorPrimary: '#6366f1',
          colorBackground: '#ffffff',
          borderRadius: '8px',
          fontFamily: 'Inter, sans-serif'
        },
        elements: {
          card: 'max-w-md mx-auto p-6 bg-white rounded-lg shadow-lg',
          formTitle: 'text-2xl font-bold text-gray-900 mb-4',
          formDescription: 'text-gray-600 mb-6',
          formInput: 'w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-indigo-500',
          formButton: 'w-full bg-indigo-600 text-white py-2 px-4 rounded-md hover:bg-indigo-700 transition-colors'
        }
      }}
    />
  );
}

Appearance Interface

Appearance Variables

Global styling variables that affect the overall theme:
interface AppearanceVariables {
  colorPrimary?: string;          // Primary brand color
  colorBackground?: string;        // Background color
  colorInputBackground?: string;   // Input field background
  colorText?: string;              // Text color
  colorInputText?: string;         // Input text color
  colorError?: string;             // Error message color
  colorSuccess?: string;           // Success message color
  borderRadius?: string;           // Global border radius
  fontFamily?: string;             // Font family
  fontSize?: string;               // Base font size
  fontWeight?: string;             // Base font weight
}
Example Usage:
<Mantlz
  formId="your-form-id"
  appearance={{
    variables: {
      colorPrimary: '#8b5cf6',
      colorBackground: '#fafafa',
      borderRadius: '12px',
      fontFamily: 'system-ui, sans-serif',
      fontSize: '14px',
      fontWeight: '500'
    }
  }}
/>

Creating a Complete Custom Theme

Here’s a step-by-step example of creating a full custom theme:
1

Define Your Theme

Create a theme object following the Theme interface:
themes/custom.ts
import { Theme } from '@mantlz/nextjs';

export const glassmorphismTheme: Theme = {
  form: {
    container: {
      maxWidth: '400px',
      width: '100%',
      margin: '0 auto',
      padding: '24px',
      borderRadius: '20px',
      border: '1px solid rgba(255, 255, 255, 0.18)',
      background: 'rgba(255, 255, 255, 0.25)',
      backdropFilter: 'blur(10px)',
      boxShadow: '0 8px 32px 0 rgba(31, 38, 135, 0.37)'
    },
    title: {
      fontSize: '24px',
      fontWeight: '700',
      color: '#1a202c',
      marginBottom: '8px',
      textAlign: 'center'
    },
    description: {
      fontSize: '14px',
      color: '#4a5568',
      marginBottom: '20px',
      textAlign: 'center'
    }
  },
  field: {
    container: {
      marginBottom: '16px'
    },
    label: {
      display: 'block',
      marginBottom: '8px',
      fontSize: '13px',
      fontWeight: '600',
      color: '#2d3748'
    },
    input: {
      width: '100%',
      padding: '12px 16px',
      borderRadius: '12px',
      border: '1px solid rgba(255, 255, 255, 0.3)',
      background: 'rgba(255, 255, 255, 0.5)',
      backdropFilter: 'blur(5px)',
      fontSize: '14px',
      color: '#1a202c',
      transition: 'all 0.3s ease',
      '&:focus': {
        outline: 'none',
        border: '1px solid rgba(99, 102, 241, 0.6)',
        boxShadow: '0 0 0 3px rgba(99, 102, 241, 0.1)'
      }
    },
    error: {
      color: '#e53e3e',
      fontSize: '12px',
      marginTop: '4px'
    }
  },
  button: {
    width: '100%',
    padding: '12px 24px',
    backgroundColor: '#6366f1',
    color: 'white',
    border: 'none',
    borderRadius: '12px',
    fontSize: '15px',
    fontWeight: '600',
    cursor: 'pointer',
    transition: 'all 0.3s ease',
    marginTop: '8px',
    '&:hover': {
      backgroundColor: '#4f46e5',
      transform: 'translateY(-2px)',
      boxShadow: '0 10px 25px rgba(99, 102, 241, 0.3)'
    },
    '&:active': {
      transform: 'translateY(0)'
    },
    '&:disabled': {
      opacity: 0.5,
      cursor: 'not-allowed'
    }
  }
};
2

Add Dark Mode Support

Include dark mode variants:
themes/custom.ts
export const glassmorphismTheme: Theme = {
  form: {
    // ... light mode styles
    containerDark: {
      maxWidth: '400px',
      width: '100%',
      margin: '0 auto',
      padding: '24px',
      borderRadius: '20px',
      border: '1px solid rgba(255, 255, 255, 0.08)',
      background: 'rgba(17, 25, 40, 0.75)',
      backdropFilter: 'blur(10px)',
      boxShadow: '0 8px 32px 0 rgba(0, 0, 0, 0.37)'
    },
    titleDark: {
      fontSize: '24px',
      fontWeight: '700',
      color: '#f7fafc',
      marginBottom: '8px',
      textAlign: 'center'
    },
    descriptionDark: {
      fontSize: '14px',
      color: '#cbd5e0',
      marginBottom: '20px',
      textAlign: 'center'
    }
  },
  field: {
    // ... light mode styles
    labelDark: {
      display: 'block',
      marginBottom: '8px',
      fontSize: '13px',
      fontWeight: '600',
      color: '#e2e8f0'
    },
    inputDark: {
      width: '100%',
      padding: '12px 16px',
      borderRadius: '12px',
      border: '1px solid rgba(255, 255, 255, 0.1)',
      background: 'rgba(45, 55, 72, 0.5)',
      backdropFilter: 'blur(5px)',
      fontSize: '14px',
      color: '#f7fafc',
      transition: 'all 0.3s ease',
      '&:focus': {
        outline: 'none',
        border: '1px solid rgba(139, 92, 246, 0.6)',
        boxShadow: '0 0 0 3px rgba(139, 92, 246, 0.1)'
      }
    }
  },
  // ... button styles
  buttonDark: {
    width: '100%',
    padding: '12px 24px',
    backgroundColor: '#8b5cf6',
    color: 'white',
    border: 'none',
    borderRadius: '12px',
    fontSize: '15px',
    fontWeight: '600',
    cursor: 'pointer',
    transition: 'all 0.3s ease',
    marginTop: '8px',
    '&:hover': {
      backgroundColor: '#7c3aed',
      transform: 'translateY(-2px)',
      boxShadow: '0 10px 25px rgba(139, 92, 246, 0.3)'
    }
  }
};
3

Use Your Theme

Since custom themes need to be added to the SDK’s theme registry, use the appearance prop instead:
app/form/page.tsx
import { Mantlz } from '@mantlz/nextjs';

export default function FormPage() {
  return (
    <div className="min-h-screen bg-gradient-to-br from-blue-50 to-purple-50 p-8">
      <Mantlz
        formId="your-form-id"
        appearance={{
          elements: {
            card: 'glassmorphism-container',
            formTitle: 'glassmorphism-title',
            formInput: 'glassmorphism-input'
          }
        }}
      />
    </div>
  );
}
And define the styles in your CSS:
globals.css
.glassmorphism-container {
  max-width: 400px;
  margin: 0 auto;
  padding: 24px;
  border-radius: 20px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(255, 255, 255, 0.25);
  backdrop-filter: blur(10px);
  box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
}

/* Add more styles... */

Real-World Examples

Vibrant Gradient Theme

A colorful theme with gradient backgrounds:
<Mantlz
  formId="your-form-id"
  appearance={{
    variables: {
      colorPrimary: '#f59e0b',
      borderRadius: '16px',
      fontFamily: 'Inter, sans-serif'
    },
    elements: {
      card: 'max-w-md mx-auto p-8 bg-gradient-to-br from-orange-400 via-pink-500 to-purple-600 rounded-2xl shadow-2xl',
      formTitle: 'text-3xl font-black text-white mb-3 drop-shadow-lg',
      formDescription: 'text-white/90 text-sm mb-8 drop-shadow',
      formLabel: 'text-white text-sm font-bold mb-2 block drop-shadow',
      formInput: 'w-full px-4 py-3 bg-white/20 backdrop-blur-sm border-2 border-white/30 rounded-xl text-white placeholder-white/60 focus:bg-white/30 focus:border-white focus:outline-none transition-all',
      formButton: 'w-full mt-6 px-6 py-4 bg-white text-purple-600 font-bold rounded-xl hover:bg-opacity-90 transform hover:scale-105 transition-all shadow-lg',
      formError: 'text-yellow-200 text-xs mt-2 font-semibold drop-shadow'
    }
  }}
/>

Pseudo-State Styling

You can style different states of inputs and buttons:
button: {
  backgroundColor: '#3b82f6',
  color: 'white',
  padding: '12px 24px',
  borderRadius: '8px',
  cursor: 'pointer',
  transition: 'all 0.2s',
  '&:hover': {
    backgroundColor: '#2563eb',
    transform: 'translateY(-2px)',
    boxShadow: '0 4px 12px rgba(59, 130, 246, 0.4)'
  },
  '&:active': {
    transform: 'translateY(0)',
    boxShadow: '0 2px 4px rgba(59, 130, 246, 0.4)'
  },
  '&:disabled': {
    backgroundColor: '#9ca3af',
    cursor: 'not-allowed',
    opacity: 0.5
  }
}

Order Form Button Styling

For order forms, you can apply special styling:
button: {
  backgroundColor: '#3b82f6',
  // ... other styles
  '&.order': {
    backgroundColor: '#10b981',
    '&:hover': {
      backgroundColor: '#059669'
    }
  }
}

Best Practices

Theme Design Guidelines

Consistency
  • Use consistent spacing scale (4px, 8px, 12px, 16px)
  • Maintain uniform border radius throughout
  • Apply consistent color palette
Accessibility
  • Ensure sufficient color contrast (WCAG AA minimum)
  • Provide clear focus states for inputs
  • Use readable font sizes (min 13px for body text)
Performance
  • Use CSS transitions for smooth interactions
  • Avoid complex backdrop filters on mobile
  • Optimize shadow usage
Responsiveness
  • Set max-width for optimal readability
  • Use relative units (em, rem) for scalability
  • Test on various screen sizes

CSS Variables

Mantlz SDK uses Radix UI color variables. You can reference these in your themes:
// Gray scale
var(--gray-1) through var(--gray-12)

// Color scales
var(--blue-1) through var(--blue-12)
var(--red-1) through var(--red-12)
var(--green-1) through var(--green-12)
var(--yellow-1) through var(--yellow-12)

// Semantic colors
var(--gray-4)   // Subtle borders
var(--gray-6)   // UI element borders
var(--gray-8)   // Hovered borders
var(--gray-9)   // Solid backgrounds
var(--gray-20)  // Text

var(--blue-9)   // Primary actions
var(--red-9)    // Errors
var(--green-9)  // Success

Tips and Tricks

You can use Tailwind utility classes in the elements prop:
<Mantlz
  formId="your-form-id"
  appearance={{
    elements: {
      card: 'max-w-lg mx-auto p-8 bg-white dark:bg-gray-900 rounded-xl shadow-lg',
      formTitle: 'text-2xl font-bold text-gray-900 dark:text-white mb-4',
      formInput: 'w-full px-4 py-2 border border-gray-300 dark:border-gray-700 rounded-lg focus:ring-2 focus:ring-blue-500'
    }
  }}
/>
Create reusable appearance configurations:
lib/theme-presets.ts
import { Appearance } from '@mantlz/nextjs';

export const darkModePreset: Appearance = {
  baseTheme: 'dark',
  variables: {
    colorPrimary: '#8b5cf6',
    colorBackground: '#1f2937'
  },
  elements: {
    card: 'bg-gray-800 border border-gray-700',
    formTitle: 'text-white',
    formInput: 'bg-gray-900 text-white border-gray-700'
  }
};

export const lightModePreset: Appearance = {
  baseTheme: 'light',
  variables: {
    colorPrimary: '#6366f1',
    colorBackground: '#ffffff'
  }
};
Use them in your components:
import { darkModePreset } from '@/lib/theme-presets';

<Mantlz formId="your-form-id" appearance={darkModePreset} />
Use responsive Tailwind classes:
<Mantlz
  formId="your-form-id"
  appearance={{
    elements: {
      card: 'w-full md:max-w-md lg:max-w-lg mx-auto p-4 md:p-8',
      formTitle: 'text-xl md:text-2xl lg:text-3xl',
      formInput: 'text-sm md:text-base'
    }
  }}
/>

Built-in Themes

Explore the pre-built themes

Props Reference

Complete props documentation

Build docs developers (and LLMs) love