DEV Community

Kyle Y. Parsotan
Kyle Y. Parsotan

Posted on

Eye-Tracking UI: Designing Gaze-Driven Interfaces That Work

Create an accessible, testable eye-tracking UI page with HTML, CSS, and JavaScript. Start with a simple HTML structure, then progressively layer on CSS for layout and styling and JavaScript for gaze-driven interactions. Below is a concise, step-by-step guide that makes the process easy to follow.

Link: https://kyl67899.github.io/EyeFollowUI/ |

Github: https://github.com/Kyl67899/webDevdailyChallenge

What you'll build (short overview)

A single page with a card-like container and one or more “eyes” (visual elements that move their pupils toward gaze/cursor).

Gaze-driven interactions: pupils follow the user’s gaze or mouse pointer; dwell detection can trigger actions; graceful fallback when no eye-tracker is available.

HTML: basic, semantic structure

Create a minimal skeleton so styling and behavior can be added incrementally.

Include a container, one or more card elements, and within each card an eye with a pupil:

container (e.g., .stage)

card (e.g., .card)

eye (e.g., .eye)

pupil (e.g., .pupil)

#0062AD


Cookie Monster




Keep markup simple and accessible (aria labels where appropriate).

CSS: layout and visual design (progressive enhancements)

Start with layout:

Center the stage and card, use flexbox or grid for alignment.

Give the card padding, border-radius, shadow, and a readable background.

Style the eye:

Shape the eye as a circle/oval with a white or light background and subtle border.

Use overflow: hidden to contain the pupil.

Style the pupil:

Make it a smaller circle, darker color, centered by default.

Use transform and transition for smooth movement when the pupil follows gaze/cursor.

Add responsive rules so the UI works on different screen sizes.

Use CSS variables for sizes and colors to make adjustments simple.

:root {
--eye-color: #000000;
--card-eye-color: #ffffff;
--background-color: #2f86f1;
--font-family: 'Arial, sans-serif';
}

  • { box-sizing: border-box; padding: 0; margin: 0; }

html {
height: 100%;
width: 100%;
}

body {
font-family: var(--font-family);
margin: 0;
padding: 0;
/* background-color: var(--background-color); */
background-color: var(--background-color);
}

.cards {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}

.card {
background-color: #fff;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
width: 300px;
height: 400px;
padding: 20px;
}

.blue-area {
background-color: var(--background-color);
height: 250px;
width: 100%;
margin-bottom: 20px;
display: flex;
justify-content: center;
align-items: center;
}

.leye,
.reye {
width: 100px;
height: 100px;
background-color: var(--card-eye-color);
border-radius: 50%;
margin: 0 10px;
position: relative;
}

.pupil {
width: 50px;
height: 50px;
background-color: var(--eye-color);
border-radius: 50%;
position: absolute;
top: 20px;
left: 20px;
}

.card h1{
font-size: 40px;
margin-bottom: 10px;
}

.card p{
font-size: 18px;
font-weight: 500;
color: #000000;
}

JavaScript: make it gaze-driven (progressive approach)

Start with a simple mouse-driven prototype:

Listen for mousemove on the stage, compute vector from eye center to pointer, clamp pupil movement to the eye’s bounds, update the pupil via CSS transform.

Use requestAnimationFrame for smooth updates and to avoid layout thrashing.

Testing and iteration

Test on different screen sizes and lighting conditions.

Validate behavior with keyboard and mouse-only navigation.

Measure robustness: latency tolerance, jitter handling, and false-dwell reduction.

Log anonymized metrics (if user-consented) to improve thresholds and UX.

Enhancements and polish

Add subtle animations for state changes (hover, dwell start/complete).

Provide configurable sensitivity and dwell time in UI settings.

Use visual affordances (ripples, outlines) to communicate gaze focus and upcoming actions.

Consider performance: minimize reflows, use transforms only, and avoid heavy per-frame computation.

Example structure summary (for quick reference)

HTML: .cards > .card > .eye > .pupil

CSS: variables for sizes, transitions for smooth pupil movement, responsive rules

JS: modular input handler (mouse fallback + gaze adapter)

Final notes

Keep interactions simple and predictable—too many autonomous movements can confuse users.

Prioritize privacy and clear consent when using camera or sensor data.

Build incrementally: validate UX with mouse first, then swap in gaze data to refine timing and thresholds.

Top comments (0)