Skip to content

Phase 4.2: Study Guides UI Migration to Plain CSS#2936

Draft
OpenStaxClaude wants to merge 17 commits intomainfrom
CORE-1704-study-guides-css-migration
Draft

Phase 4.2: Study Guides UI Migration to Plain CSS#2936
OpenStaxClaude wants to merge 17 commits intomainfrom
CORE-1704-study-guides-css-migration

Conversation

@OpenStaxClaude
Copy link
Copy Markdown
Contributor

@OpenStaxClaude OpenStaxClaude commented Apr 23, 2026

Summary

This PR migrates study guides components from styled-components to plain CSS, following the hybrid approach from PLAIN_CSS_MIGRATION_GUIDE.md. This is Phase 4.2 of the CSS migration work and builds on top of Phase 4.1 (PR #2932).

Progress

✅ Completed:

  • StudyGuidesListElement - Individual highlight display with dynamic color-coded borders
  • StudyGuidesCTA - Call-to-action banner with buttons and info section

🚧 In Progress / Remaining:

  • ShowStudyGuides - Main container with scroll handling
  • StudyGuides - Main listing component with nested styling
  • Filters - Chapter and color filter dropdowns
  • StudyGuidesPopUp - Main popup modal container
  • StudyGuidesToasts - Toast notifications

Migration Approach

  • Keep theme.ts in JavaScript for type safety and dynamic theme access
  • Replace styled-components with plain CSS files imported for side effects
  • Bind CSS variables from theme values when needed for dynamic theming
  • Convert theme.breakpoints.mobile to standard media queries (@media screen and (max-width: 75em))
  • Preserve all print styles, accessibility features, and functionality

Key Features

  • Dynamic highlight colors: StudyGuidesListElement binds highlight border colors as CSS variables based on the highlight color
  • Theme colors: CTA buttons bind deep green colors from theme
  • Responsive breakpoints: Converted to standard CSS media queries
  • Print styles: Preserved @media print rules, CTA hidden in print
  • Accessibility: Maintained hidden-but-accessible class for screen readers

Related

Test Plan

See comprehensive testing guide in the Jira ticket description. Key areas:

  • Study guides modal appearance and functionality
  • Highlight listing with correct color-coded borders
  • CTA banner styling and responsiveness
  • Filters and print functionality
  • Responsive design across screen sizes

🤖 Generated with Claude Code

OpenStaxClaude and others added 11 commits April 20, 2026 21:45
Start CSS migration for practice questions by migrating ProgressBarItem
component from styled-components to plain CSS with hybrid approach.

- Created ProgressBarItem.css with plain CSS styles
- Converted styled-components to className-based styling
- Bind CSS variables from theme for dynamic values
- Use classNames library for conditional classes

Related to CORE-1703

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Convert QuestionNavigation index from styled-components to plain CSS
- Create index.css with wrapper styles and media queries
- Remove Button.tsx styled wrapper (no longer needed)
- Update SkipAndSubmitButtons to import Button directly from components
- Preserve all existing functionality and props
- Child components (ShowAnswerButton, NextButton, FinishButton) already use plain Button component

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Migrated the following components from styled-components to plain CSS:
- ProgressBar container component (src/app/content/practiceQuestions/components/ProgressBar/index.tsx)
- Question component (src/app/content/practiceQuestions/components/Question.tsx)

Changes:
- Created index.css for ProgressBar container with responsive margin styles
- Created Question.css with styles for question wrapper, content, and answers
- Updated ProgressBar/index.tsx to use className instead of styled-components
- Updated Question.tsx to use CSS classes and CSS variables for theming
- Bound CSS variables from theme values for dynamic theming (padding, colors)
- Exported QuestionWrapper, QuestionContent, and AnswersWrapper for backward compatibility with tests
- Preserved all existing props and functionality

Follows the hybrid approach from PLAIN_CSS_MIGRATION_GUIDE.md where theme
remains in JavaScript and components bind CSS variables as needed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Migrated IntroScreen.tsx to use plain CSS with IntroScreen.css
- Migrated NextSectionMessage.tsx to use plain CSS with NextSectionMessage.css
- Migrated FinalScreen.tsx to use plain CSS with FinalScreen.css
- Migrated EmptyScreen.tsx to use plain CSS with EmptyScreen.css
- Migrated ShowPracticeQuestions.tsx to use plain CSS with ShowPracticeQuestions.css
- Migrated Filters.tsx wrapper component to use plain CSS with Filters.css

All components now use plain CSS with CSS variables for theming,
following the hybrid approach from PLAIN_CSS_MIGRATION_GUIDE.md.
Removed styled-components dependencies and converted Typography
mixins (textRegularStyle, textRegularSize) to plain CSS equivalents.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
- Remove duplicate outline property (line 30-31)
- Reorder selectors to fix specificity warnings
- Group all hover states together at the end for proper specificity

Resolves all 8 stylelint errors:
- no-descending-specificity (7 errors)
- declaration-block-no-duplicate-properties (1 error)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Question.tsx:
- Replace 'any' types with proper TypeScript types
- Add QuestionContentProps interface for QuestionContent component
- Use React.HTMLAttributes for QuestionWrapper and AnswersWrapper

ShowPracticeQuestions.tsx:
- Export SectionTitle (alias for MaybeSectionTitle) for backward compatibility
- Export QuestionsWrapper and QuestionsHeader for test compatibility
- All exports maintain proper TypeScript typing

Resolves all TypeScript compilation errors and eslint warnings:
- 3 @typescript-eslint/no-explicit-any warnings fixed
- 3 TS2614 module export errors fixed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The tests were failing because they were looking for component types
(QuestionWrapper, AnswersWrapper, QuestionsWrapper, QuestionsHeader)
but the code was using inline JSX elements (<form>, <div>, <h3>).

Changes:
- Updated Question.tsx to use QuestionWrapper and AnswersWrapper components
- Updated QuestionWrapper to be a forwardRef component to support ref prop
- Updated ShowPracticeQuestions.tsx to use QuestionsWrapper and QuestionsHeader
- Moved wrapper component exports before they are used in the file

This fixes all 3 failing test cases:
- ShowPracticeQuestions › renders Intro screen
- Question › renders all components
- Question › renders properly with selected and submitted answer

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Update ShowPracticeQuestions.tsx

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fix 5 issues identified by Copilot code review:

1. **Filters.css**: Increased selector specificity to override styled-components
   - Changed `.practice-questions-chapter-filters` to `.practice-questions-chapter-filters.practice-questions-chapter-filters`
   - Ensures padding reset always wins over styled-components injection

2. **Question.tsx**: Preserve className prop in wrapper components
   - Updated QuestionWrapper and AnswersWrapper to merge incoming className with component class
   - Maintains backward compatibility and composability for tests

3. **ShowPracticeQuestions.css**: Increased specificity for body styles
   - Changed `.show-practice-questions-body` to `.show-practice-questions-body.show-practice-questions-body`
   - Ensures overrides win against PopupBody styled-component

4. **ShowPracticeQuestions.css**: Corrected section title typography
   - Fixed font-size from 2.4rem/3rem to 1.8rem/2.5rem (desktop)
   - Fixed mobile font-size from unspecified to 1.6rem/2rem
   - Now matches h4Style from Typography/Headings.legacy.ts as intended

5. **ShowPracticeQuestions.tsx**: Preserve className in wrapper components
   - Updated QuestionsWrapper and QuestionsHeader to merge className props
   - Maintains backward compatibility for test usage

All changes maintain existing functionality while improving CSS specificity
and component composability.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Remove unused classname handling
@TomWoodward TomWoodward temporarily deployed to rex-web-core-1704-study-m7j6cc April 23, 2026 16:10 Inactive
@TomWoodward TomWoodward temporarily deployed to rex-web-core-1704-study-m7j6cc April 23, 2026 16:30 Inactive
OpenStaxClaude and others added 2 commits April 23, 2026 13:00
Migrate initial study guides components from styled-components to plain CSS:

✅ StudyGuidesListElement
- Created StudyGuidesListElement.css with responsive and print styles
- Bind dynamic highlight border color as CSS variable
- Convert mobile breakpoints to standard media queries
- Preserve accessibility with hidden-but-accessible class

✅ StudyGuidesCTA
- Created StudyGuidesCTA.css for all CTA banner components
- Migrate 8 styled components (wrapper, buttons, info, arrows)
- Bind theme colors (deep green, text colors) as CSS variables
- Preserve print styles (CTA hidden in print)
- Deleted styles.tsx file

Migration follows the hybrid approach from PLAIN_CSS_MIGRATION_GUIDE.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Migrate ShowStudyGuides.tsx from styled-components to plain CSS:

✅ ShowStudyGuides (StudyGuidesBody)
- Created ShowStudyGuides.css with study-guides-specific styling
- Replaced styled(PopupBody) with direct PopupBody usage + className
- Bind theme background color as CSS variable (--study-guides-bg)
- Convert mobile breakpoint to standard media query (max-width: 75em)
- Preserve print styles (white background, FiltersList padding)
- Export PopupBody as StudyGuidesBody for test compatibility

Migration follows the hybrid approach from PLAIN_CSS_MIGRATION_GUIDE.md

Related: CORE-1704

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@RoyEJohnson RoyEJohnson force-pushed the CORE-1704-study-guides-css-migration branch from b2f74c6 to 51f1614 Compare April 23, 2026 18:01
@TomWoodward TomWoodward temporarily deployed to rex-web-core-1704-study-m7j6cc April 23, 2026 18:01 Inactive
RoyEJohnson

This comment was marked as resolved.

Copy link
Copy Markdown
Contributor

@RoyEJohnson RoyEJohnson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you figure out which is the right color spec, and why two were put in?
Also look at the other errors; if the "important" is needed, we can put a disabling comment in.

src/app/content/studyGuides/components/StudyGuidesListElement.css
 36:3   ⚠  Unexpected duplicate "color"                         declaration-block-no-duplicate-properties
 66:38  ✖  Unexpected unknown pseudo-class selector ":global"   selector-pseudo-class-no-unknown         

src/app/content/studyGuides/components/StudyGuidesCTA/StudyGuidesCTA.css
 28:20  ⚠  Unexpected !important   declaration-no-important

- Remove duplicate color property in StudyGuidesListElement.css
  (kept theme.color.text.black as it overrides text.default)
- Replace :global() pseudo-class with standard descendant selector
  (not using CSS Modules, so :global is not supported)
- Add stylelint disable comment for !important in print styles
  (needed to override other display styles in print media)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@OpenStaxClaude
Copy link
Copy Markdown
Contributor Author

@RoyEJohnson I've fixed all the CSS linting errors:

Fixed Issues

1. Duplicate color property (StudyGuidesListElement.css:36)

Root cause: During migration, I included both colors from the original styled-component:

  • ${textRegularStyle}color: theme.color.text.default
  • Explicit color: theme.color.text.black

Fix: Removed the duplicate. Kept only theme.color.text.black since that's what was effectively applied (the second declaration overrode the first in the original code).

2. Unknown pseudo-class :global (StudyGuidesListElement.css:66)

Root cause: Used CSS Modules syntax (:global()) but this file doesn't use CSS Modules.

Fix: Changed .study-guides-list-element-content :global(.content-excerpt) to standard descendant selector .study-guides-list-element-content .content-excerpt

3. Unexpected !important (StudyGuidesCTA.css:28)

Root cause: Print styles need !important to override other display styles.

Fix: Added stylelint disable comment: /* stylelint-disable-next-line declaration-no-important -- needed to override other display styles in print */

All changes have been pushed to the branch and the linter now passes for these files.

@TomWoodward TomWoodward temporarily deployed to rex-web-core-1704-study-m7j6cc April 23, 2026 18:16 Inactive
@TomWoodward TomWoodward temporarily deployed to rex-web-core-1704-study-m7j6cc April 23, 2026 18:25 Inactive
Copy link
Copy Markdown
Contributor

@RoyEJohnson RoyEJohnson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the test needs to be updated to look for the right thing rather than a Styled.STudyGuidesCTAWrapper.

src/app/content/studyGuides/components/StudyGuidesCTA/index.spec.tsx:8:25 - error TS2307: Cannot find module './styles' or its corresponding type declarations.

8 import * as Styled from './styles';

The StudyGuidesCTA component was migrated from styled-components to
plain CSS, so the ./styles module no longer exists. Updated the test
to query by className 'study-guides-cta-wrapper' instead of the
removed Styled.StudyGuidesCTAWrapper component.

Resolves TypeScript error: Cannot find module './styles'

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@OpenStaxClaude
Copy link
Copy Markdown
Contributor Author

@RoyEJohnson Fixed the test import error!

Issue

The test was importing from ./styles which no longer exists after the CSS migration:

import * as Styled from './styles';

And then using:

expect(() => component.root.findByType(Styled.StudyGuidesCTAWrapper)).toThrow();

Fix

Removed the styled-components import and updated the test to query by className instead:

expect(() => component.root.findByProps({ className: 'study-guides-cta-wrapper' })).toThrow();

This matches the migration pattern where Styled.StudyGuidesCTAWrapper became <div className="study-guides-cta-wrapper">.

The TypeScript compilation error should now be resolved.

@TomWoodward TomWoodward temporarily deployed to rex-web-core-1704-study-m7j6cc April 23, 2026 18:35 Inactive
@TomWoodward TomWoodward temporarily deployed to rex-web-core-1704-study-m7j6cc April 23, 2026 18:46 Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants