UX Issue

Mobile Users Can't Log In: Claude's Desktop-Only Flow

Hard-coded click events broke on touch devices; we rebuilt the login UI responsively and reclaimed mobile traffic.

January 15, 2025 5 min read

The problem

A fitness app lost 73% of their mobile users after launching a new login flow. Mobile users reported the login button was "broken" - they'd tap it repeatedly with no response. Support tickets flooded in: "Can't access my workouts!", "App frozen on login screen!". Analytics showed mobile users had a 91% bounce rate on the login page, while desktop worked perfectly. The company was losing $42,000/week in mobile subscriptions.

How AI created this issue

The developer had asked Claude to create a "modern login form with hover effects". Claude generated desktop-focused code with mouse-only interactions:


// Claude's desktop-only login implementation
const LoginForm = () => {
  const [showPassword, setShowPassword] = useState(false);
  
  useEffect(() => {
    // Custom dropdown using mouse events only
    const dropdown = document.querySelector('.custom-dropdown');
    dropdown.addEventListener('mouseenter', () => {
      dropdown.classList.add('open');
    });
    
    dropdown.addEventListener('mouseleave', () => {
      dropdown.classList.remove('open');
    });
    
    // Password visibility toggle with hover
    const passwordField = document.querySelector('.password-field');
    passwordField.addEventListener('mouseenter', (e) => {
      if (e.clientX > passwordField.offsetWidth - 50) {
        setShowPassword(true);
      }
    });
    
    // Submit button with custom click handling
    const submitBtn = document.querySelector('.submit-btn');
    submitBtn.onclick = (e) => {
      e.preventDefault();
      // Fancy ripple effect
      const ripple = document.createElement('span');
      ripple.className = 'ripple';
      ripple.style.left = e.clientX - e.target.offsetLeft + 'px';
      ripple.style.top = e.clientY - e.target.offsetTop + 'px';
      submitBtn.appendChild(ripple);
      
      setTimeout(() => handleSubmit(), 600); // Wait for animation
    };
  }, []);
  
  return (
    <form className="login-form">
      <div className="custom-dropdown">
        <span>Select Account Type</span>
        {/* Dropdown opens on hover only */}
      </div>
      
      <input type="password" className="password-field" />
      
      <button className="submit-btn">
        Sign In
      </button>
    </form>
  );
};

Claude used mouseenter/mouseleave events that don't exist on touch devices. The custom onclick handler prevented mobile Safari's touch handling. The hover-based UI patterns were impossible to activate on phones. Claude never mentioned touch events or mobile compatibility.

The solution

  1. Touch-first event handling: Rebuilt with proper touch support:
    
    // Mobile-friendly implementation
    const LoginForm = () => {
      const handleInteraction = (callback) => {
        return {
          onClick: callback,
          onTouchEnd: (e) => {
            e.preventDefault(); // Prevent ghost clicks
            callback(e);
          }
        };
      };
      
      const handleSubmit = async (e) => {
        e.preventDefault();
        const formData = new FormData(e.target);
        
        try {
          setLoading(true);
          await login(Object.fromEntries(formData));
        } catch (error) {
          setError(error.message);
        } finally {
          setLoading(false);
        }
      };
      
      return (
        <form onSubmit={handleSubmit} className="login-form">
          <select 
            className="w-full p-3 border rounded"
            name="accountType"
            required
          >
            <option value="">Select Account Type</option>
            <option value="personal">Personal</option>
            <option value="trainer">Trainer</option>
          </select>
          
          <div className="relative">
            <input
              type={showPassword ? 'text' : 'password'}
              className="w-full p-3 border rounded pr-12"
              name="password"
              required
            />
            <button
              type="button"
              className="absolute right-3 top-3"
              {...handleInteraction(() => setShowPassword(!showPassword))}
              aria-label="Toggle password visibility"
            >
              {showPassword ? '👁️' : '👁️‍🗨️'}
            </button>
          </div>
          
          <button
            type="submit"
            className="w-full p-3 bg-blue-500 text-white rounded"
            disabled={loading}
          >
            {loading ? 'Signing in...' : 'Sign In'}
          </button>
        </form>
      );
    };
  2. Native form elements: Replaced custom dropdowns with native selects that work everywhere
  3. Progressive enhancement: Added touch gestures as enhancements, not requirements
  4. Mobile-first CSS: Redesigned with thumb-friendly tap targets (min 44x44px)
  5. Device testing lab: Set up BrowserStack for testing on real devices

The results

  • Mobile login success rate jumped from 9% to 94%
  • Recovered $168,000/month in mobile revenue
  • Support tickets dropped 89% as mobile users could actually log in
  • Mobile session duration increased 4.3x
  • App store rating improved from 2.1 to 4.6 stars
  • Page load time improved 2.1s by removing unnecessary animations

The team learned that AI tools typically generate code for desktop browsers since that's where developers test. They now specify "mobile-first" in all prompts and test on actual devices before deployment. Touch interaction is their default, with mouse events as the enhancement.

Ready to fix your codebase?

Let us analyze your application and resolve these issues before they impact your users.

Get Diagnostic Assessment →