CSS customization requires:
- Enterprise plan subscription
embedSigningWhiteLabelfeature flag enabledallowWhitelabellingparameter set totruein 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
- Check feature flag: Ensure
embedSigningWhiteLabelis enabled - Verify Enterprise plan: CSS customization requires Enterprise subscription
- Validate JSON: Ensure embed data is valid JSON
- 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
