Skip to main content

LearningClues (opens in a new tab)

Making an AI chat usable for every student, on any screen

StudyClues from a phone to an ultra-wide desktop. The layout reflows at each of the five breakpoints rather than scaling down.
Role
Frontend Engineer
Timeline
June 2026
Team
  • Product Designer
  • Frontend Engineer (me!)
Tools
Skills
  • Frontend Engineering
  • Accessibility
  • Responsiveness
  • Design Systems
  • Agentic Coding

Overview

StudyClues is LearningClues' student-facing AI chat for higher education. Unlike general-purpose tools (e.g., Claude, ChatGPT), its answers are grounded in a student's own course materials, with citations back to the exact lecture moment or document section they came from.

An illustration of course-grounding in StudyClues.

The procurement process for higher-ed is often long-winded and ambiguous

Ahead of the Fall 2026 semester, two R1 universities sent us lists of accessibility blockers. Conformance was the primary barrier to adoption so the objective seemed clear:

“clear the accessibility blockers”

My audit changed the scope. The blockers were not isolated defects. They traced back to an interface built for a single 1440px laptop screen, which was also the reason tablet and mobile users could not use the product at all. Clearing the accessibility failures and making the interface responsive turned out to be the same work. And because the layout was being rebuilt from the ground up, a UI refresh that had been overdue for more than a year came with it.

Impact

Procurement unblocked at 2 R1 universities where conformance had stalled adoption

Layout shift reduced to 0.00 CLS when switching conversations

Usable at 400% zoom with no loss of content or functionality

Now works across 5 breakpoints from phones to ultra-wide

Resolved 6/6 accessibility issues found in the audit, 2 of them blocking core flows entirely

Problem

Accessibility conformance is a business problem, not a “polish” problem

The DOJ's ADA Title II rule (opens in a new tab) sets WCAG 2.1 Level AA as the standard for public universities, with an April 2027 compliance deadline. Institutions evaluating StudyClues were not just treating accessibility as a “nice-to-have". This is why two R1 universities sent us lists of blockers solely related to accessibility.

I ran an accessibility audit of the existing system because a list assembled from outside the product is unlikely to be complete and found six issues, two of which made core flows unusable outright rather than merely difficult.

The six issues the audit found

IssueWCAG SCLevelSeveritySource
Conversation history is marked up as headings rather than a list1.3.1 Info and Relationships (opens in a new tab)AMajorMy audit
Markdown in answers skips heading levels1.3.1 Info and Relationships (opens in a new tab)AMajorMy audit
Components sit outside any landmark, with no way to skip navigation1.3.1 Info and Relationships (opens in a new tab)AMajorSchool-reported
Starting a new chat clips content behind the header at 200% zoom1.4.4 Resize Text (opens in a new tab)AABlockerSchool-reported
Code blocks force two-dimensional scrolling at 400% zoom1.4.10 Reflow (opens in a new tab)AABlockerMy audit
The message field jumps position when switching conversations——MinorMy audit

The blockers shared a root cause

  1. At 200% zoom on a 1280px viewport, starting a new chat clipped content behind a hidden overflow, leaving the flow unusable. That is a direct failure of WCAG 2.1 SC 1.4.4 Resize Text (opens in a new tab) (AA).
  2. At 400% zoom, any response containing a code block introduced two-dimensional scrolling, failing SC 1.4.10 Reflow (opens in a new tab) (AA).

Neither was a local bug. Content was being hidden and forced into two-dimensional scrolling because the page structure assumed one viewport width, the 1440px laptop screen the interface had originally been built for. The same assumption was why tablet and mobile users could not use StudyClues either!

The old StudyClues at 200% zoom. The header has wrapped onto two lines and grown tall enough to cover the top row of suggested question cards, whose text is sliced in half. The mode buttons below the message field are cut off by the bottom of the window.
Starting a new chat: the top row of suggested questions is unreachable behind the header.
The old StudyClues showing an answer at 200% zoom. The response text runs underneath the message field and is cut off mid-sentence, and the mode buttons are cropped by the bottom of the window.
The same zoom level in a conversation: the answer runs underneath the message field.

The app had a broken structure for screen readers

Beyond the blockers, the structure underneath the interface was inconsistent. Three issues shared a root cause: the document's programmatic structure did not describe the page a user was actually on. All three touch SC 1.3.1 Info and Relationships (opens in a new tab) (A):

  1. The sidebar's conversation history was marked up as a hierarchy of headings rather than a list.
  2. Markdown rendered in chat responses skipped heading levels, because the LLM generating the answers had no knowledge of the surrounding page structure.
  3. Components sat outside any landmark region, and there was no way to skip past navigation to the chat itself.

A visual refresh that had been deferred for over a year now became feasible

The accessibility blockers and the responsiveness failure were the same defect observed from two directions, which meant they could not be fixed separately. This is also what expanded the project. Rebuilding the layout to satisfy reflow meant rebuilding it for every screen size, and rebuilding it for every screen size meant the interface was being reconstructed anyway.

As such, a visual refresh that had been deferred for over a year now became feasible inside the same four weeks rather than a separate initiative.

Before: the original screen. Four navigation items crowd the header, the sidebar lists a dozen near-identical past chats, and the suggested questions sit in rows of uneven width.
After: the rebuilt screen. The header carries the course name and a single button, past chats are grouped under Recents, and the suggested questions form an even two-by-two grid.
The default chat screen before and after the rebuild. Drag the divider to compare.

Defining "Done"

One sentence framed the work:

“the interface should not be the reason a student does not return”

Once the audit established that the blockers and the responsiveness failure were the same problem, the scope resolved into three commitments that had to be delivered concurrently:

Rebuilding for Every Screen

The old interface was built for a 1440px laptop screen, and that assumption was what produced the accessibility blockers as much as the missing mobile support. Rebuilding it meant deciding, per component, what should change and at which point.

Mobile-first, with data-driven breakpoints

I built up from the smallest viewport rather than down from the 1440px layout. That ordering matters: starting at mobile forces you to decide what is essential before you have room for anything else.

We started from Material Design's guidelines (opens in a new tab), then adjusted against usage data on the viewport sizes students were actually using and against what competing AI interfaces supported. That gave us five breakpoints:

The sidebar changes layout, not just size

The sidebar was the component that needed an alternate layout the most. Until the compact breakpoint (1024px), it's a drawer: hidden by default, and sliding out over a dimmed backdrop when opened.

Above the compact breakpoint (1024px), it stays in place with collapsed and expanded states so the user can reclaim screen real estate when they do not need the conversation history. The user's choice is persisted to localStorage, so the layout a returning student sees is the one they left, with the sidebar animating smoothly into its stored state on load.

On a phone, the menu button slides the sidebar out over the chat and dims everything behind it. Choosing an item, pressing Escape or tapping the backdrop closes it again.
Above the compact breakpoint the sidebar stays put, collapsing to a rail of icons and expanding again as the chat column takes back the width.

Alternate layouts for content that risked overflow

Some elements could not simply reflow and instead required alternate layouts:

Supporting zoom is a responsiveness problem

Supporting 400% zoom on a 1280px viewport is equivalent to laying out for a 320px-wide screen, which is why the mobile-first work and the reflow fix were the same work rather than distinct efforts!

StudyClues at 100% zoom on a 1280px viewport: the sidebar sits open beside the chat, and the suggested questions form a two-by-two grid above the message field.

Remediating Accessibility Blockers

Accessibility was the foundation for this project, not an afterthought. I ran the audit that defined the scope, made the implementation decisions, and verified the result by hand.

Fixing the 2 critical blockers

  1. At 200% zoom on a 1280px viewport, starting a new chat clipped content behind a hidden overflow. The fix was the layout restructure described in Rebuilding for Every Screen: the sidebar became a drawer, the suggested queries reflowed, and the header shed weight.
  2. At 400% zoom, responses containing code blocks forced two-dimensional scrolling, failing SC 1.4.10 Reflow (opens in a new tab) (AA). Long unbroken strings do not respond to container-level layout work, so this took targeted CSS overrides on the markdown renderer for word breaking and overflow.

Structure the screen reader could finally rely on

  1. I rebuilt the sidebar's conversation history as a nested unordered list. This is a common mistake, and it matters because a screen reader user navigating by heading is trying to move through content, not through navigation!
  2. Rather than trying to constrain the LLM's (often indeterministic) output, I used component overrides on react-markdown (opens in a new tab) to remap heading levels dynamically so they fit the page's outline.
  3. I placed every component within an appropriate landmark and wrapped the chat area, message field and messages together, in a main element, then added a "Skip to Main Content" link so keyboard users could bypass navigation entirely.
The Headings tab of the HeadingsMap panel, reading a StudyClues conversation. Level 1 is "StudyClues for CLIMATE 102 001 WN 2023"; under it level 2 "Chat Messages" holds a level 3 for each turn, "You said:" and "StudyClues said:", with level 4 "Was this response helpful?" beneath each answer; a second level 2 reads "Message Entry Box". No level is skipped.
Heading outline
The Landmarks tab of the same panel, listing three regions for the page: Sidebar marked navigation, Banner marked banner, and Main marked main.
Landmark regions

A drawer that traps keyboard users is worse than no drawer

A drawer that traps keyboard users is worse than no drawer. I wrapped the sidebar in focus-trap-react (opens in a new tab), a lightweight and well-established library, rather than hand-rolling focus containment. That was a deliberate choice about where to spend effort!

The drawer dismisses on Escape, on selecting a navigation item, and on clicking outside, which keeps SC 2.1.2 No Keyboard Trap (opens in a new tab) (A) satisfied. On close, focus returns to the element that opened it, so a keyboard user is not dropped back at the top of the document.

One fix that was not a “conformance issue”

There was a layout shift on conversation switching that failed no success criterion. I fixed it anyway :)

A user relying on screen magnification sees a fraction of the viewport at a time, and a message field that travels to the center of the screen and back has, from their perspective, disappeared and reappeared somewhere else. Users with cognitive or attention-related disabilities face the same disruption for different reasons. The skeleton screen holds the layout in place and, through its shimmering animation, communicates that something is loading rather than leaving the movement unexplained.

Results

The rebuild shipped to production at the end of the four weeks, and conversations with two R1 universities that had stalled on conformance were able to move forward.

Every core flow is operable by keyboard and screen reader

All six issues from the audit are closed, including the two that had made flows unusable by keyboard and screen reader outright. I ran every core flow with VoiceOver and by keyboard, then ran automated tooling across the rebuilt interface: WAVE, aXe DevTools, and HeadingsMap for document structure.

The interface now works from mobile to ultra-wide

A product that had been built for a 1440px laptop screen now supports five breakpoints from mobile to ultra-wide, and holds up under zoom to 400% on a 1280px viewport, the equivalent of laying out for a 320px-wide screen. Students on tablets and phones can use the platform, which was not previously true at any zoom level.

StudyClues from a phone to an ultra-wide desktop. The layout reflows at each of the five breakpoints rather than scaling down.

Layout shift on conversation switching is gone

Switching conversations now measures 0.00 CLS (opens in a new tab) in the Chrome DevTools Performance panel. The message field stays where it is while history loads, and a shimmering skeleton screen communicates a loading state rather than leaving the movement unexplained.

Switching to another conversation. The message field holds its position while a shimmering skeleton stands in for the messages still loading above it.

Several components are standardized

Several components built here were general enough to belong to more than one product. The sidebar, skip link, modal, accordion, and badge were extracted into the LearningClues design system's component library, built against the same DTCG design tokens (opens in a new tab) the rest of our products consume. As a bonus, the accessibility work in them is inherited rather than rebuilt each time!

Reflections