Input
Clean, accessible text inputs with subtle inset shadows, smooth focus rings, comprehensive validation states, animated error messages, and first-class dark mode support with glassmorphism effects.
Basic Input
The simplest form: just add sol-input class to any <input> element.
<input type="text" class="sol-input" placeholder="Enter your name…">
Input Structure
Use sol-input-group as a flex wrapper to pair inputs with labels.
This ensures consistent spacing (0.4rem gap), alignment, and accessibility.
<div class="sol-input-group"> <label class="sol-label">Email address</label> <input type="email" class="sol-input" placeholder="you@example.com"> </div>
Shadows and Depth
Solora inputs use a dual-shadow technique for depth: an inset shadow (0.05 opacity inset) creates a subtle "inset" feel, while an outer shadow (0.05 opacity) provides lift. This creates a refined, layered appearance without being overdone.
/* Light mode depth */
.sol-input {
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05),
0 2px 8px rgba(0, 0, 0, 0.05);
}
/* Dark mode with glassmorphism */
:root.dark .sol-input {
box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.05),
0 4px 12px rgba(0, 0, 0, 0.4);
Focus and Hover States
Hover changes the background and border slightly. On focus, the input gains a
colored glow ring (using --color-focus-glow) and the border switches to --color-primary.
.sol-input:hover {
border-color: rgba(0, 0, 0, 0.2);
background: var(--color-bg-hover, #ffffff);
}
.sol-input:focus {
border-color: var(--color-primary, #0071e3);
box-shadow: 0 0 0 4px var(--color-focus-glow, rgba(0, 113, 227, 0.15)),
0 2px 8px rgba(0, 0, 0, 0.05);
}
Disabled State
Disabled inputs show reduced opacity (0.5) and a lighter background.
The cursor changes to not-allowed to indicate unavailability.
<input type="text" class="sol-input" placeholder="Can't type here…" disabled>
Read-only State
The :read-only state is distinct from :disabled.
Read-only inputs are selectable and copyable, but not editable. They have a flat appearance
without the lifted shadow, and no hover effects.
<input type="text" class="sol-input" value="Text" readonly>
readonly when the value should be copiable or selectable. Use disabled
when the input should be truly inactive (won't submit in forms, not focusable in some contexts).
Error States
There are two ways to show errors: the sol-input-error class (simple border change)
or the is-invalid class (full error styling with glow). Use is-invalid for
progressive validation and error messages.
<div class="sol-input-group">
<label class="sol-label">Password</label>
<input type="password" class="sol-input is-invalid">
<div class="sol-error-message" style="display: block;">
Password must be at least 8 characters
</div>
</div>
Error Messages
The sol-error-message class provides styled error text below the input.
Error messages fade in smoothly with a 0.2s animation and use the --color-danger color.
/* Error message styling */
.sol-error-message {
color: var(--color-danger, #ff453a);
font-size: 0.75rem;
font-weight: 500;
margin-top: 0.2rem;
margin-left: 0.2rem;
display: none; /* Shown with JavaScript or inline style */
animation: solFadeIn 0.2s ease-out;
}
@keyframes solFadeIn {
from { opacity: 0; transform: translateY(-5px); }
to { opacity: 1; transform: translateY(0); }
}
Number Inputs (Hidden Spin Buttons)
For type="number" inputs, the browser's default spin buttons are hidden
via -webkit-appearance: none and -moz-appearance: textfield.
This provides a cleaner, modern appearance.
<input type="number" class="sol-input" placeholder="Enter quantity">
Placeholder Styling
Placeholders use 0.3 opacity of the text color for subtle guidance without overwhelming the user. This works consistently in both light and dark modes.
.sol-input::placeholder {
color: var(--color-text-dark, #000);
opacity: 0.3;
}
:root.dark .sol-input::placeholder {
color: var(--color-text-light, #fff);
opacity: 0.3;
}
Label Styling
Labels are small (0.85rem), semi-bold (500 weight), and use 0.6 opacity for Apple-inspired subtlety. They're positioned above the input with a small 0.2rem left margin for alignment.
.sol-label {
font-size: 0.85rem;
font-weight: 500;
color: var(--color-text-dark, #000);
opacity: 0.6;
margin-left: 0.2rem;
}
Dark Mode with Glassmorphism
In dark mode, inputs use a glassmorphism effect: a semi-transparent background (rgba(44, 44, 46, 0.9))
with backdrop-filter: blur(12px). This creates visual depth and a premium feel
while maintaining text readability.
Toggle to dark mode to see the glassmorphism effect in action.
/* Dark mode glassmorphism */
:root.dark .sol-input {
background: rgba(28, 28, 30, 0.8);
color: var(--color-text-light, #fff);
border: 1px solid rgba(255, 255, 255, 0.15);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.05),
0 4px 12px rgba(0, 0, 0, 0.4);
}
:root.dark .sol-input:focus {
border-color: var(--color-primary-dark, #0a84ff);
box-shadow: 0 0 0 4px var(--color-focus-glow-dark, rgba(10, 132, 255, 0.2)),
0 4px 12px rgba(0, 0, 0, 0.5);
}
CSS Classes Reference
| Class / Attribute | Type | Description |
|---|---|---|
sol-input | Required | Base input styles — always include |
sol-input-group | Container | Flex wrapper for label + input with 0.4rem gap |
sol-label | Label | Styled label element above input |
sol-input-error | State | Simple error styling (red border) |
is-invalid | State | Full error mode with glow; use with error message |
sol-error-message | Message | Error text below input; display with inline style |
readonly | Attribute | HTML attribute for read-only state |
disabled | Attribute | HTML attribute for disabled state |
CSS Variables for Customization
Use these CSS variables to customize input appearance across your entire site:
:root {
/* Text and background */
--color-text-dark: #000;
--color-text-light: #fff;
--color-bg: #fefefe;
--color-bg-hover: #ffffff;
--color-bg-readonly: #f9f9f9;
/* Primary and danger colors */
--color-primary: #0071e3;
--color-focus-glow: rgba(0, 113, 227, 0.15);
--color-danger: #ff453a;
--color-error-glow: rgba(255, 69, 58, 0.15);
}
:root.dark {
--color-primary-dark: #0a84ff;
--color-focus-glow-dark: rgba(10, 132, 255, 0.2);
}
Validation Example
A complete example showing error message handling with JavaScript:
// Validate on blur
const input = document.querySelector('.sol-input');
const errorMsg = input.parentElement.querySelector('.sol-error-message');
input.addEventListener('blur', function() {
if (this.value.length < 8) {
this.classList.add('is-invalid');
errorMsg.textContent = 'Must be at least 8 characters';
errorMsg.style.display = 'block';
} else {
this.classList.remove('is-invalid');
errorMsg.style.display = 'none';
}
});
HTML5 Required Validation
Solora automatically detects and styles inputs with the HTML5 required attribute.
When a required field is empty or invalid, the JavaScript automatically applies the error state
with the is-invalid class and shows an error message.
<div class="sol-input-group"> <label class="sol-label">Email (required)</label> <input type="email" class="sol-input" placeholder="you@example.com" required> <div class="sol-error-message">Email is required and must be valid</div> </div>
Automatic Validation with JavaScript
Solora provides a helper function to automatically handle required field validation. It applies the error state and shows/hides error messages based on field validity.
import { initValidation } from '@kerkhoff-ict/solora/dist/index.js';
// Initialize automatic validation for all required inputs
initValidation();
// Listens for:
// - 'blur' event: validates when field loses focus
// - 'input' event: validates in real-time while typing
// - form 'submit': prevents submission if fields are invalid
Manual Validation Control
You can manually trigger validation state on individual inputs if needed:
// Get input and error elements
const emailInput = document.querySelector('input[type="email"]');
const errorMsg = emailInput.parentElement.querySelector('.sol-error-message');
// Validate
if (!emailInput.value) {
emailInput.classList.add('is-invalid');
errorMsg.textContent = 'Email is required';
errorMsg.style.display = 'block';
} else if (!emailInput.checkValidity()) {
emailInput.classList.add('is-invalid');
errorMsg.textContent = 'Please enter a valid email';
errorMsg.style.display = 'block';
} else {
emailInput.classList.remove('is-invalid');
errorMsg.style.display = 'none';
}
Validation Events
Listen for validation events to customize behavior or trigger additional actions:
// Listen for validation state changes
document.addEventListener('sol:validationChange', (event) => {
const { input, isValid, message } = event.detail;
console.log(`Field ${input.name} is ${isValid ? 'valid' : 'invalid'}`);
console.log(`Message: ${message}`);
});
Validation with Custom Rules
For complex validation beyond HTML5 validation, use data attributes:
<input type="text" class="sol-input" required minlength="4" data-error-message="Username must be at least 4 characters" >
Initialisation
// Inputs are automatically initialized with initAll()
// No manual initialization needed!
import('@kerkhoff-ict/solora/dist/index.js')
.then(sol => sol.initAll());
Accessibility
- Always pair inputs with a visible
<label>using thesol-labelclass or usearia-label. - Use semantic input types:
type="email",type="password",type="number", etc. - Error messages should be associated with inputs via
aria-describedbyfor screen readers. - The focus ring provides clear visual indication; don't remove it.
- Readonly inputs can be tabbed to and selected, making them useful for display-only data.
Input Type Reference
| Input Type | Supported | Notes |
|---|---|---|
text | ✓ | Default, works perfectly |
email | ✓ | Browser validation + Solora styling |
password | ✓ | Masked input with full support |
number | ✓ | Spin buttons hidden for clean look |
tel | ✓ | Telephone number with mobile keyboard |
url | ✓ | URL validation + Solora styling |
search | ✓ | Works like text with search semantics |
date | ~ | Works but browser native picker overrides some styles |