Styling Guide
The PaySight Widget provides extensive styling and theming options to match your application’s design. This guide covers all available styling options and best practices.
Theme Configuration
The widget’s appearance can be customized through the theme
configuration option:
const config = {
// ... other config options
theme: {
// Google Font link (optional)
font: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap',
// Custom CSS styles
css: {
// Your custom styles
},
// Pre-defined theme name (optional)
themeName: 'light' // or 'dark'
}
};
Basic Styling
Root Variables
Define global variables for consistent styling:
const config = {
theme: {
css: {
":root": {
"--primary-color": "#3b82f6",
"--error-color": "#ef4444",
"--text-color": "#0f172a",
"--border-color": "#e5e7eb",
"--background-color": "#ffffff",
"--input-height": "40px",
"--border-radius": "6px"
}
}
}
};
Container Styles
Style the widget container:
const config = {
theme: {
css: {
".widget-container": {
padding: "20px",
backgroundColor: "var(--background-color)",
borderRadius: "8px",
boxShadow: "0 1px 3px rgba(0, 0, 0, 0.1)"
}
}
}
};
Customize form input fields:
const config = {
theme: {
css: {
input: {
height: "var(--input-height)",
padding: "0 12px",
fontSize: "16px",
borderRadius: "var(--border-radius)",
border: "1px solid var(--border-color)",
color: "var(--text-color)",
transition: "border-color 0.2s ease",
"&::placeholder": {
color: "#94a3b8"
},
"&:focus": {
outline: "none",
borderColor: "var(--primary-color)",
boxShadow: "0 0 0 3px rgba(59, 130, 246, 0.1)"
}
}
}
}
};
Style the submit button:
const config = {
theme: {
css: {
button: {
backgroundColor: "var(--primary-color)",
color: "#ffffff",
padding: "0 16px",
height: "var(--input-height)",
borderRadius: "var(--border-radius)",
fontSize: "16px",
border: "none",
cursor: "pointer",
transition: "background-color 0.2s ease",
"&:hover": {
backgroundColor: "#2563eb"
},
"&:focus": {
outline: "none",
boxShadow: "0 0 0 3px rgba(59, 130, 246, 0.1)"
}
}
}
}
};
Advanced Styling
Component-Specific Styles
Style specific widget components:
const config = {
theme: {
css: {
// Card input field
"[ev-component=card]": {
gap: "16px",
// Card number field
".field[ev-name=number]": {
position: "relative",
"& input": {
paddingLeft: "48px" // Space for card icon
},
"& .icon": {
position: "absolute",
left: "12px",
top: "50%",
transform: "translateY(-50%)",
width: "24px",
height: "24px"
}
},
// Expiry and CVC fields
".field[ev-name=expiry], .field[ev-name=cvc]": {
"& input": {
textAlign: "center"
}
}
},
// Address fields
"[ev-component=address]": {
display: "grid",
gridTemplateColumns: "1fr 1fr",
gap: "16px",
".field[ev-name=street]": {
gridColumn: "1 / -1"
}
}
}
}
};
State-Based Styling
Style different field states:
const config = {
theme: {
css: {
// Focus state
"input:focus": {
outline: "none",
borderColor: "var(--primary-color)",
boxShadow: "0 0 0 3px rgba(59, 130, 246, 0.1)"
},
// Error state
".field[ev-valid=false]": {
"& input": {
borderColor: "var(--error-color)",
color: "var(--error-color)"
},
"& .error": {
color: "var(--error-color)",
fontSize: "12px",
marginTop: "4px"
}
},
// Disabled state
"input:disabled": {
backgroundColor: "#f8fafc",
cursor: "not-allowed",
opacity: 0.7
},
// Loading state
".loading": {
opacity: 0.7,
pointerEvents: "none"
}
}
}
};
Responsive Design
Implement responsive styles:
const config = {
theme: {
css: {
// Base styles
".widget-container": {
width: "100%",
maxWidth: "500px",
margin: "0 auto",
padding: "20px"
},
// Mobile styles
"@media (max-width: 640px)": {
".widget-container": {
padding: "16px"
},
input: {
fontSize: "14px"
},
button: {
width: "100%"
}
}
}
}
};
Pre-defined Themes
Use built-in themes as a starting point:
// Light theme (default)
const config = {
theme: {
themeName: 'light'
}
};
// Dark theme
const config = {
theme: {
themeName: 'dark'
}
};
Dynamic Theme Updates
Update the widget’s theme after initialization:
// Update theme
widget.update({
theme: {
css: {
":root": {
"--primary-color": "#0ea5e9"
}
}
}
});
// Switch to dark theme
widget.update({
theme: {
themeName: 'dark'
}
});
Best Practices
1. Use CSS Variables
Define and use CSS variables for consistent styling:
const config = {
theme: {
css: {
":root": {
"--primary": "#3b82f6",
"--primary-dark": "#2563eb",
"--error": "#ef4444",
"--success": "#22c55e"
},
button: {
backgroundColor: "var(--primary)",
"&:hover": {
backgroundColor: "var(--primary-dark)"
}
}
}
}
};
2. Maintain Consistency
Create a theme object for consistent values:
const theme = {
colors: {
primary: "#3b82f6",
error: "#ef4444",
text: "#0f172a",
border: "#e5e7eb"
},
spacing: {
sm: "8px",
md: "16px",
lg: "24px"
},
borderRadius: {
sm: "4px",
md: "6px",
lg: "8px"
}
};
const config = {
theme: {
css: {
input: {
padding: theme.spacing.md,
borderRadius: theme.borderRadius.md,
borderColor: theme.colors.border
}
}
}
};
3. Follow Accessibility Guidelines
Ensure your styles maintain accessibility:
const config = {
theme: {
css: {
// Ensure sufficient color contrast
button: {
backgroundColor: "#2563eb",
color: "#ffffff",
// Visible focus indicators
"&:focus": {
outline: "2px solid #60a5fa",
outlineOffset: "2px"
}
},
// Clear error states
".error": {
color: "#ef4444",
fontWeight: "500"
}
}
}
};
Next Steps