Skip to main content
Documenso’s Enterprise plan allows you to customize the appearance of embedded signing and authoring interfaces using CSS variables and custom CSS.
CSS customization requires:
  • Enterprise plan subscription
  • embedSigningWhiteLabel feature flag enabled
  • allowWhitelabelling parameter set to true in embed route

CSS Variables Schema

Documenso uses CSS custom properties (variables) based on HSL color values for theming:
interface CssVariables {
  // Base colors
  background?: string;        // Base background color
  foreground?: string;        // Base text color
  
  // UI elements
  muted?: string;            // Muted/subtle background
  mutedForeground?: string;  // Muted/subtle text
  popover?: string;          // Popover/dropdown background
  popoverForeground?: string; // Popover/dropdown text
  
  // Cards
  card?: string;             // Card background
  cardBorder?: string;       // Card border
  cardBorderTint?: string;   // Card border highlight
  cardForeground?: string;   // Card text
  
  // Field cards (signing fields)
  fieldCard?: string;        // Field card background
  fieldCardBorder?: string;  // Field card border
  fieldCardForeground?: string; // Field card text
  
  // Widgets (signing sidebar)
  widget?: string;           // Widget background
  widgetForeground?: string; // Widget text
  
  // Borders and inputs
  border?: string;           // Default border color
  input?: string;            // Input field border
  
  // Action colors
  primary?: string;          // Primary action/button
  primaryForeground?: string; // Primary button text
  secondary?: string;        // Secondary action/button
  secondaryForeground?: string; // Secondary button text
  accent?: string;           // Accent/highlight
  accentForeground?: string; // Accent text
  destructive?: string;      // Destructive/danger action
  destructiveForeground?: string; // Destructive text
  
  // Other
  ring?: string;             // Focus ring color
  warning?: string;          // Warning/alert color
  radius?: string;           // Border radius (in rem units)
}

Color Format

CSS variables use HSL (Hue, Saturation, Lightness) format:
const cssVars = {
  primary: '#3b82f6',        // Hex color input
  background: 'rgb(255, 255, 255)', // RGB input
  foreground: 'hsl(222, 47%, 11%)' // HSL input
};

// Documenso converts all formats to HSL internally:
// --primary: 217 91% 60%
// --background: 0 0% 100%
// --foreground: 222 47% 11%

Basic Usage

Embedding with CSS Variables

function createStyledEmbedUrl(token: string) {
  const embedData = {
    // Your brand colors
    cssVars: {
      primary: '#3b82f6',      // Blue primary
      background: '#ffffff',    // White background
      foreground: '#0f172a',    // Dark text
      border: '#e2e8f0',        // Light gray borders
      radius: '0.75rem'         // Rounded corners
    }
  };

  const hash = btoa(encodeURIComponent(JSON.stringify(embedData)));
  return `https://app.documenso.com/embed/sign/${token}#${hash}`;
}

Complete Theme Example

const brandTheme = {
  cssVars: {
    // Base
    background: '#ffffff',
    foreground: '#09090b',
    
    // Muted elements
    muted: '#f4f4f5',
    mutedForeground: '#71717a',
    
    // Cards
    card: '#ffffff',
    cardBorder: '#e4e4e7',
    cardForeground: '#09090b',
    
    // Widgets
    widget: '#fafafa',
    widgetForeground: '#09090b',
    
    // Borders
    border: '#e4e4e7',
    input: '#e4e4e7',
    
    // Primary actions (your brand color)
    primary: '#6366f1',        // Indigo
    primaryForeground: '#ffffff',
    
    // Secondary actions
    secondary: '#f4f4f5',
    secondaryForeground: '#18181b',
    
    // Accent
    accent: '#8b5cf6',         // Purple accent
    accentForeground: '#ffffff',
    
    // Destructive
    destructive: '#ef4444',
    destructiveForeground: '#ffffff',
    
    // Focus ring
    ring: '#6366f1',
    
    // Border radius
    radius: '0.5rem'
  }
};

Custom CSS

For advanced customization, inject custom CSS:
const embedData = {
  css: `
    /* Custom font */
    .embed--Root {
      font-family: 'Inter', -apple-system, sans-serif;
    }
    
    /* Hide powered by badge */
    .branding-logo {
      display: none !important;
    }
    
    /* Custom button styles */
    button[type="submit"] {
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      border: none;
      font-weight: 600;
      letter-spacing: 0.025em;
    }
    
    /* Field highlighting */
    .field-card:hover {
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
      transform: translateY(-2px);
      transition: all 0.2s ease;
    }
  `,
  cssVars: {
    primary: '#667eea'
  }
};

Dark Mode

Disable Dark Mode

const embedData = {
  darkModeDisabled: true, // Force light mode only
  cssVars: {
    background: '#ffffff',
    foreground: '#000000'
  }
};

Custom Dark Theme

const darkTheme = {
  darkModeDisabled: false, // Allow dark mode
  cssVars: {
    // Dark mode colors
    background: '#0a0a0a',
    foreground: '#fafafa',
    
    card: '#141414',
    cardBorder: '#262626',
    cardForeground: '#fafafa',
    
    widget: '#0f0f0f',
    widgetForeground: '#fafafa',
    
    muted: '#171717',
    mutedForeground: '#a1a1aa',
    
    border: '#262626',
    input: '#262626',
    
    primary: '#8b5cf6',
    primaryForeground: '#ffffff',
    
    ring: '#8b5cf6',
    radius: '0.5rem'
  }
};

CSS Class Targeting

Documenso uses specific CSS classes for different embed components:
/* Root container */
.embed--Root { }

/* Document viewer area */
.embed--DocumentViewer { }

/* Signing widget sidebar */
.embed--DocumentWidgetContainer { }
.embed--DocumentWidget { }
.embed--DocumentWidgetHeader { }
.embed--DocumentWidgetContent { }
.embed--DocumentWidgetForm { }
.embed--DocumentWidgetFooter { }

/* Action buttons area */
.embed--Actions { }

/* Special states */
.embed--DocumentCompleted { }
.embed--DocumentRejected { }
.embed--RecipientExpired { }
.embed--WaitingForTurn { }

Example: Custom Widget Styling

const embedData = {
  css: `
    /* Make widget stand out */
    .embed--DocumentWidget {
      background: linear-gradient(to bottom, #ffffff, #f9fafb);
      box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
      border-radius: 1rem;
    }
    
    /* Custom header */
    .embed--DocumentWidgetHeader h3 {
      color: #6366f1;
      font-size: 1.5rem;
      font-weight: 700;
    }
    
    /* Styled form inputs */
    .embed--DocumentWidgetForm input {
      border: 2px solid #e5e7eb;
      border-radius: 0.5rem;
      padding: 0.75rem;
    }
    
    .embed--DocumentWidgetForm input:focus {
      border-color: #6366f1;
      box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
    }
  `
};

Brand Examples

Tech Startup Theme

const techStartupTheme = {
  cssVars: {
    primary: '#7c3aed',        // Purple
    background: '#ffffff',
    foreground: '#1e1b4b',
    card: '#faf5ff',           // Light purple tint
    border: '#ddd6fe',
    radius: '0.75rem'
  },
  css: `
    .embed--Root {
      font-family: 'Space Grotesk', sans-serif;
    }
    button {
      text-transform: uppercase;
      letter-spacing: 0.05em;
      font-weight: 700;
    }
  `
};

Corporate/Enterprise Theme

const corporateTheme = {
  cssVars: {
    primary: '#1e40af',        // Deep blue
    secondary: '#6b7280',      // Gray
    background: '#f9fafb',
    foreground: '#111827',
    card: '#ffffff',
    border: '#d1d5db',
    radius: '0.25rem'          // Sharp corners
  },
  css: `
    .embed--Root {
      font-family: 'Roboto', 'Helvetica Neue', sans-serif;
    }
    button {
      text-transform: none;
      font-weight: 500;
    }
  `
};

Creative Agency Theme

const creativeTheme = {
  cssVars: {
    primary: '#ec4899',        // Pink
    accent: '#f59e0b',         // Orange
    background: '#fffbeb',     // Warm white
    foreground: '#78350f',     // Brown
    card: '#ffffff',
    border: '#fde68a',         // Yellow border
    radius: '1.5rem'           // Very rounded
  },
  css: `
    .embed--Root {
      font-family: 'Poppins', sans-serif;
    }
    
    .embed--DocumentWidget {
      background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
    }
    
    button {
      border-radius: 9999px;
      padding-left: 2rem;
      padding-right: 2rem;
      font-weight: 600;
    }
  `
};

Implementation Utilities

TypeScript Helper

import { colord } from 'colord';

function createEmbedUrl(
  token: string,
  theme: {
    cssVars?: Record<string, string>;
    css?: string;
    darkModeDisabled?: boolean;
  }
) {
  const embedData = {
    darkModeDisabled: theme.darkModeDisabled ?? false,
    css: theme.css,
    cssVars: theme.cssVars
  };

  const hash = btoa(encodeURIComponent(JSON.stringify(embedData)));
  return `https://app.documenso.com/embed/sign/${token}#${hash}`;
}

// Usage
const url = createEmbedUrl('token-123', {
  cssVars: {
    primary: '#3b82f6',
    background: '#ffffff'
  },
  css: '.embed--Root { font-family: Inter; }'
});

React Hook

import { useMemo } from 'react';

interface Theme {
  cssVars?: Record<string, string>;
  css?: string;
  darkModeDisabled?: boolean;
}

export function useEmbedUrl(token: string, theme?: Theme) {
  return useMemo(() => {
    if (!theme) {
      return `https://app.documenso.com/embed/sign/${token}`;
    }

    const embedData = {
      darkModeDisabled: theme.darkModeDisabled ?? false,
      css: theme.css,
      cssVars: theme.cssVars
    };

    const hash = btoa(encodeURIComponent(JSON.stringify(embedData)));
    return `https://app.documenso.com/embed/sign/${token}#${hash}`;
  }, [token, theme]);
}

// Usage
function SigningPage({ token }: { token: string }) {
  const embedUrl = useEmbedUrl(token, {
    cssVars: {
      primary: '#3b82f6',
      radius: '0.75rem'
    }
  });

  return <iframe src={embedUrl} className="w-full h-screen" />;
}

Testing Themes

Browser Console Testing

// Test theme changes in browser console
const theme = {
  cssVars: {
    primary: '#ef4444',
    background: '#fef2f2'
  }
};

const embedData = btoa(encodeURIComponent(JSON.stringify(theme)));
window.location.hash = embedData;

Theme Preview Component

import { useState } from 'react';

function ThemePreview({ token }: { token: string }) {
  const [primaryColor, setPrimaryColor] = useState('#3b82f6');
  const [radius, setRadius] = useState('0.5');

  const embedUrl = useMemo(() => {
    const embedData = {
      cssVars: {
        primary: primaryColor,
        radius: `${radius}rem`
      }
    };
    const hash = btoa(encodeURIComponent(JSON.stringify(embedData)));
    return `https://app.documenso.com/embed/sign/${token}#${hash}`;
  }, [token, primaryColor, radius]);

  return (
    <div>
      <div className="controls">
        <label>
          Primary Color:
          <input
            type="color"
            value={primaryColor}
            onChange={(e) => setPrimaryColor(e.target.value)}
          />
        </label>
        <label>
          Border Radius: {radius}rem
          <input
            type="range"
            min="0"
            max="2"
            step="0.25"
            value={radius}
            onChange={(e) => setRadius(e.target.value)}
          />
        </label>
      </div>
      <iframe src={embedUrl} className="w-full h-screen" />
    </div>
  );
}

Best Practices

Performance

  • Keep custom CSS minimal
  • Avoid complex selectors
  • Use CSS variables instead of inline styles
  • Don’t override too many default styles

Accessibility

const accessibleTheme = {
  cssVars: {
    // Ensure sufficient contrast (WCAG AA: 4.5:1 for text)
    background: '#ffffff',
    foreground: '#1f2937',  // 12:1 contrast ratio
    
    // Maintain visible focus indicators
    ring: '#3b82f6',
    
    // Distinguishable interactive elements
    primary: '#2563eb',
    secondary: '#6b7280'
  },
  css: `
    /* Ensure focus is always visible */
    *:focus-visible {
      outline: 2px solid var(--ring);
      outline-offset: 2px;
    }
  `
};

Browser Compatibility

  • CSS variables work in all modern browsers
  • Test in Safari, Chrome, Firefox, Edge
  • Provide fallbacks for older browsers if needed

Troubleshooting

Styles Not Applying

  1. Check feature flag: Ensure embedSigningWhiteLabel is enabled
  2. Verify Enterprise plan: CSS customization requires Enterprise subscription
  3. Validate JSON: Ensure embed data is valid JSON
  4. Check encoding: Use btoa(encodeURIComponent(JSON.stringify(data)))

Dark Mode Issues

// Force light mode if dark mode colors aren't working
const embedData = {
  darkModeDisabled: true,
  cssVars: { /* light theme only */ }
};

Color Format Issues

// Documenso accepts multiple formats:
const validColors = {
  hex: '#3b82f6',
  rgb: 'rgb(59, 130, 246)',
  hsl: 'hsl(217, 91%, 60%)'
};

// All are converted to HSL internally

Next Steps

Direct Links

Learn about embedding signing links

React SDK

Build themed React components