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>
📋 Read-only vs Disabled Use 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.

Password must be at least 8 characters
<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 / AttributeTypeDescription
sol-inputRequiredBase input styles — always include
sol-input-groupContainerFlex wrapper for label + input with 0.4rem gap
sol-labelLabelStyled label element above input
sol-input-errorStateSimple error styling (red border)
is-invalidStateFull error mode with glow; use with error message
sol-error-messageMessageError text below input; display with inline style
readonlyAttributeHTML attribute for read-only state
disabledAttributeHTML 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.

Email is required and must be valid
Password is required
<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

♿ Best practices
  • Always pair inputs with a visible <label> using the sol-label class or use aria-label.
  • Use semantic input types: type="email", type="password", type="number", etc.
  • Error messages should be associated with inputs via aria-describedby for 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 TypeSupportedNotes
textDefault, works perfectly
emailBrowser validation + Solora styling
passwordMasked input with full support
numberSpin buttons hidden for clean look
telTelephone number with mobile keyboard
urlURL validation + Solora styling
searchWorks like text with search semantics
date~Works but browser native picker overrides some styles