Learn about how you can customise card components.
Card components come with responsive and accessible default styling, but are designed to be fully customisable.
All styling configurations support multiple states to provide dynamic visual feedback:
interface StateStyles {
base?: CSSProperties; // Default appearance
valid?: CSSProperties; // When field passes validation
invalid?: CSSProperties; // When field fails validation
}
interface ComponentStyles {
base?: CSSProperties; // Container styles
valid?: CSSProperties; // Valid state container
invalid?: CSSProperties; // Invalid state container
input?: CSSProperties; // Input element specific styles
}
All styling options use React's CSSProperties
interface, providing:
- Type safety: IntelliSense support and compile-time validation.
- Comprehensive properties: Access to all CSS properties.
- Pseudo-selectors: Support for
:hover
,:focus
,:active
states. - Camel case conversion: Automatic conversion from camelCase to kebab-case.
All field components inherit from FieldComponentConfig
and support comprehensive styling:
interface FieldComponentConfig {
// Container styling with state support
componentStyles?: ComponentStyles;
// Input element styling with states
inputStyles?: StateStyles;
// Label styling with states
labelStyles?: StateStyles;
// Label positioning
labelPosition?: 'above' | 'below' | 'left' | 'right';
isFloatingLabel?: boolean;
// Error message styling
invalidTextStyles?: CSSProperties;
invalidTextPosition?: 'above' | 'below' | 'left' | 'right';
// Icon customisation
validIconSrc?: string;
invalidIconSrc?: string;
}
Here's an example of a customised card number component.
const cardNumberConfig: CardNumberComponentConfig = {
// Container styling
componentStyles: {
base: {
backgroundColor: '#f8f9fa',
borderRadius: '8px',
padding: '16px',
boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
},
valid: {
borderColor: '#28a745',
backgroundColor: '#f8fff8'
},
invalid: {
borderColor: '#dc3545',
backgroundColor: '#fff8f8'
}
},
// Input field styling
inputStyles: {
base: {
fontSize: '18px',
fontWeight: '500',
color: '#2c3e50',
border: '2px solid #e9ecef',
borderRadius: '6px',
padding: '12px 16px',
transition: 'all 0.3s ease'
},
valid: {
borderColor: '#28a745',
':focus': {
borderColor: '#20c997',
boxShadow: '0 0 0 3px rgba(40, 167, 69, 0.1)'
}
},
invalid: {
borderColor: '#dc3545',
':focus': {
borderColor: '#c82333',
boxShadow: '0 0 0 3px rgba(220, 53, 69, 0.1)'
}
}
},
// Label styling
labelStyles: {
base: {
fontSize: '14px',
fontWeight: '600',
color: '#495057',
marginBottom: '8px',
textTransform: 'uppercase',
letterSpacing: '0.5px'
},
invalid: {
color: '#dc3545'
}
},
// Floating label configuration
isFloatingLabel: true,
labelPosition: 'above',
// Error message styling
invalidTextStyles: {
fontSize: '12px',
color: '#dc3545',
fontStyle: 'italic',
marginTop: '4px'
},
// Icon customisation
showHintIcon: true,
hintIconSrc: 'https://example.com/card-icon.svg'
};
const submitButtonConfig: CardSubmitComponentConfig = {
submitText: 'Complete payment',
styles: {
base: {
backgroundColor: '#6c5ce7',
color: '#ffffff',
fontSize: '16px',
fontWeight: '600',
padding: '14px 32px',
borderRadius: '8px',
border: 'none',
cursor: 'pointer',
transition: 'all 0.2s ease',
textTransform: 'uppercase',
letterSpacing: '0.5px'
},
hover: {
backgroundColor: '#5a52d5',
transform: 'translateY(-1px)',
boxShadow: '0 4px 12px rgba(108, 92, 231, 0.3)'
},
disabled: {
backgroundColor: '#95a5a6',
cursor: 'not-allowed',
transform: 'none',
boxShadow: 'none'
}
}
}
};
const countryConfig: CountrySelectionComponentConfig = {
// Base field styling
componentStyles: {
base: {
position: 'relative',
width: '100%'
}
},
// Dropdown container styling
dropdownStyles: {
backgroundColor: '#ffffff',
border: '1px solid #dee2e6',
borderRadius: '0 0 12px 12px',
boxShadow: '0 8px 25px rgba(0, 0, 0, 0.15)',
maxHeight: '250px',
overflowY: 'auto',
zIndex: 1000
},
// Dropdown option styling
dropdownOptionStyles: {
unselected: {
padding: '12px 16px',
cursor: 'pointer',
borderBottom: '1px solid #f8f9fa',
transition: 'background-color 0.2s ease'
},
hover: {
backgroundColor: '#e3f2fd',
borderLeft: '3px solid #2196f3'
},
selected: {
backgroundColor: '#e8f5e8',
color: '#2e7d32',
fontWeight: '600',
borderLeft: '3px solid #4caf50'
}
}
};
const checkboxConfig: CheckboxComponentConfig = {
label: 'Save payment method for future use',
checkedColor: '#4caf50',
labelStyles: {
checked: {
color: '#2e7d32',
fontWeight: '500'
},
unchecked: {
color: '#6c757d',
fontWeight: '400'
}
}
};
const advancedInputStyles = {
base: {
fontSize: '16px',
padding: '12px',
// Pseudo-selectors using key prefixes
':hover': {
borderColor: '#007bff'
},
':focus': {
borderColor: '#0056b3',
boxShadow: '0 0 0 3px rgba(0, 123, 255, 0.1)'
},
':active': {
transform: 'translateY(1px)'
},
'::placeholder': {
color: '#6c757d',
fontStyle: 'italic'
}
}
};
const responsiveStyles = {
base: {
fontSize: '16px',
padding: '12px',
// Use CSS custom properties for responsive behaviour
'--mobile-padding': '8px',
'--desktop-padding': '16px',
// Media queries via CSS-in-JS (if supported)
'@media (max-width: 768px)': {
fontSize: '14px',
padding: 'var(--mobile-padding)'
},
'@media (min-width: 769px)': {
padding: 'var(--desktop-padding)'
}
}
};
const typographyTheme = {
// Font families
primaryFont: 'Inter, system-ui, -apple-system, sans-serif',
monospaceFont: 'SF Mono, Monaco, monospace',
// Font sizes
fontSizes: {
xs: '12px',
sm: '14px',
base: '16px',
lg: '18px',
xl: '20px'
},
// Line heights
lineHeights: {
tight: '1.2',
normal: '1.5',
relaxed: '1.7'
}
};
// Apply to components
const cardNumberConfig = {
inputStyles: {
base: {
fontFamily: typographyTheme.primaryFont,
fontSize: typographyTheme.fontSizes.base,
lineHeight: typographyTheme.lineHeights.normal
}
},
labelStyles: {
base: {
fontFamily: typographyTheme.primaryFont,
fontSize: typographyTheme.fontSizes.sm,
lineHeight: typographyTheme.lineHeights.tight
}
}
};
const brandColors = {
primary: '#6c5ce7',
secondary: '#00b894',
accent: '#fd79a8',
neutral: {
50: '#f8f9fa',
100: '#e9ecef',
200: '#dee2e6',
500: '#6c757d',
900: '#212529'
},
semantic: {
success: '#00b894',
warning: '#fdcb6e',
error: '#e17055',
info: '#74b9ff'
}
};
// Apply brand colours
const brandedComponentStyles = {
base: {
backgroundColor: brandColors.neutral[50],
borderColor: brandColors.neutral[200]
},
valid: {
borderColor: brandColors.semantic.success,
color: brandColors.semantic.success
},
invalid: {
borderColor: brandColors.semantic.error,
color: brandColors.semantic.error
}
};
const animatedStyles = {
base: {
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
transform: 'translateY(0)',
opacity: 1
},
invalid: {
transform: 'translateX(2px)',
animation: 'shake 0.5s ease-in-out'
}
};
// Add keyframes via CSS injection
const keyframes = `
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-2px); }
75% { transform: translateX(2px); }
}
`;