← Back to all tutorials

Styling Text Inputs

Restyle text inputs, textareas, and other text-type inputs — custom borders, focus animations, floating labels, and placeholder styles.

Styling Text Inputs

Text inputs are the most common form element on the web — search bars, login forms, contact forms. In this episode you will learn how to completely restyle text inputs with custom borders, animated focus states, floating labels, and beautiful placeholder text.

Resetting Browser Defaults

input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="tel"],
input[type="url"],
input[type="search"],
textarea {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    border: none;
    outline: none;
    background: none;
    font-family: inherit;
    font-size: inherit;
    color: inherit;
    width: 100%;
    box-sizing: border-box;
}

The appearance: none property strips all browser-applied styles from the input. Combined with resetting border, outline, and background, this gives us a completely blank canvas. We also inherit the font family and size from the parent so inputs match the surrounding text.

Base Input Style

.styled-form input[type="text"],
.styled-form input[type="email"],
.styled-form input[type="password"],
.styled-form textarea {
    padding: 12px 16px;
    border: 2px solid #e5e7eb;
    border-radius: 8px;
    font-size: 15px;
    color: #1f2937;
    background: #fff;
    transition: border-color 0.3s ease, box-shadow 0.3s ease;
}

.styled-form textarea {
    min-height: 120px;
    resize: vertical;
}

A clean, modern input with rounded corners, a light gray border, and smooth transitions for the focus state. Textareas get a minimum height and vertical-only resizing.

Placeholder Styling

.styled-form input::placeholder,
.styled-form textarea::placeholder {
    color: #9ca3af;
    font-style: italic;
    opacity: 1;  /* Firefox sets placeholder opacity to less than 1 */
}

The ::placeholder pseudo-element styles the placeholder text. Setting opacity: 1 is important because Firefox applies a default opacity less than 1 to placeholders, making them lighter than expected.

Focus State — Glowing Border

.styled-form input:focus,
.styled-form textarea:focus {
    border-color: #4A90D9;
    box-shadow: 0 0 0 3px rgba(74, 144, 217, 0.15);
}

When the input is focused, the border turns blue and a subtle glow appears around it using box-shadow. The box-shadow approach is better than outline because it respects border-radius and can be transitioned smoothly.

Focus Glow vs Outline

TechniqueFollows border-radiusCan be transitionedColor customizable
outlineSometimes (browser-dependent)NoYes
box-shadowAlwaysYesYes

Underline Input Style

.input-underline {
    border: none;
    border-bottom: 2px solid #d1d5db;
    border-radius: 0;
    padding: 12px 4px;
    background: transparent;
    transition: border-color 0.3s ease;
}

.input-underline:focus {
    border-bottom-color: #4A90D9;
    box-shadow: none;
}

A minimal, Material Design-inspired input with only a bottom border. This style works well on light backgrounds and gives a clean, modern look.

Animated Underline with Pseudo-Element

.input-wrapper {
    position: relative;
}

.input-wrapper::after {
    content: "";
    position: absolute;
    bottom: 0;
    left: 50%;
    width: 0;
    height: 2px;
    background: #4A90D9;
    transition: width 0.3s ease, left 0.3s ease;
}

.input-wrapper:focus-within::after {
    width: 100%;
    left: 0;
}

This creates a blue underline that expands from the center when the input is focused. The :focus-within pseudo-class activates when any child element inside the wrapper receives focus.

Floating Label Pattern

<div class="floating-group">
    <input type="text" id="name" placeholder=" " required>
    <label for="name">Full Name</label>
</div>

.floating-group {
    position: relative;
    margin-bottom: 24px;
}

.floating-group input {
    padding: 20px 16px 8px;
    border: 2px solid #e5e7eb;
    border-radius: 8px;
    font-size: 15px;
    width: 100%;
    transition: border-color 0.3s ease;
}

.floating-group label {
    position: absolute;
    left: 16px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 15px;
    color: #9ca3af;
    pointer-events: none;
    transition: all 0.2s ease;
}

/* Float up when focused or has content */
.floating-group input:focus + label,
.floating-group input:not(:placeholder-shown) + label {
    top: 8px;
    transform: translateY(0);
    font-size: 11px;
    color: #4A90D9;
    font-weight: 600;
}

The floating label sits inside the input as a placeholder and floats up to the top when the input is focused or has content. The trick uses :placeholder-shown — when the placeholder is not visible (meaning the user has typed something), the label stays floated up even after focus leaves. The placeholder is set to a single space (" ") so it is technically present but invisible.

Input with Icon

.input-icon-wrapper {
    position: relative;
}

.input-icon-wrapper input {
    padding-left: 44px;
}

.input-icon-wrapper .icon {
    position: absolute;
    left: 14px;
    top: 50%;
    transform: translateY(-50%);
    color: #9ca3af;
    font-size: 18px;
    pointer-events: none;
    transition: color 0.3s ease;
}

.input-icon-wrapper:focus-within .icon {
    color: #4A90D9;
}

The icon is positioned absolutely inside the wrapper and extra left padding on the input prevents the text from overlapping it. The icon changes color when the input is focused using :focus-within.

Key Takeaways

  • appearance: none strips all browser default styles so you can build from scratch
  • Use box-shadow instead of outline for focus rings that follow border-radius and can be transitioned
  • ::placeholder styles the placeholder text — set opacity: 1 for cross-browser consistency
  • The floating label pattern uses :placeholder-shown and :focus to animate the label position
  • :focus-within activates styles on a parent when any child element is focused
  • Always inherit font-family and font-size so inputs match the surrounding design