# Radio Button Testing Guide


**Last Updated:** 2025-11-20

This guide provides testing steps and troubleshooting for radio button visual state issues across all tools pages.

## Visual State Testing Steps

### 1. Basic Functionality Test

1. Navigate to any tools page with radio buttons (e.g., `/tools/mehrwertsteuer-rechner`)
2. Locate a radio button group (e.g., "Ich gebe ein: Netto/Brutto")
3. Click a radio button
4. **Expected:** Radio button should show checked state immediately (blue circle with white dot, blue label border, light blue label background)
5. Click another radio in the same group
6. **Expected:** Previous radio should uncheck, new radio should check (only one checked at a time)

### 2. Alpine.js Model Sync Test

1. Open browser DevTools Console
2. Navigate to tools page with radio buttons
3. Find radio with `x-model` binding (e.g., `x-model="inputType"`)
4. Click radio button
5. In console, check Alpine.js model: `Alpine.$data(document.querySelector('[x-data]')).inputType`
6. **Expected:** Value should match radio `value` attribute when checked
7. Verify DOM `checked` attribute: `document.querySelector('input[value="brutto"]').checked`
8. **Expected:** Should be `true` for checked radio, `false` for others in same group

### 3. CSS Visual State Test

1. Open browser DevTools Elements panel
2. Select radio button element
3. Check computed styles when checked:
   - `border-color` should be `rgb(77, 142, 243)` (blue `#4D8EF3`)
   - `background-color` should be `rgb(77, 142, 243)` (blue `#4D8EF3`)
   - `::before` pseudo-element should have white dot (`background-color: white`)
4. Check label styles when radio inside is checked:
   - `border-color` should be `rgb(77, 142, 243)` (blue `#4D8EF3`)
   - `background-color` should be `rgb(248, 250, 255)` (light blue `#f8faff`)
5. **Expected:** All styles should match checked state immediately after click

### 4. Radio Group Behavior Test

1. Navigate to page with radio group (e.g., `/tools/arbeitstage-rechner`)
2. Click first radio in group
3. **Expected:** Only first radio checked
4. Click second radio in same group
5. **Expected:** First radio unchecked, second radio checked (only one checked)
6. Verify all radios in group have same `name` attribute

### 5. Cross-Page Consistency Test

Test radio buttons on multiple tools pages:
- `/tools/mehrwertsteuer-rechner` - Pattern 2: Input type, country, VAT rate radios
- `/tools/arbeitstage-rechner` - Pattern 2: Working days per week radios
- `/tools/stundenlohnrechner` - Pattern 1: Calculation type radios (`.radio-item`)
- `/tools/tvoed_sue` - Pattern 1: Various radio groups (`.radio-item`)

**Expected:** All Pattern 2 radios should have consistent visual behavior, Pattern 1 radios should work correctly

## Browser DevTools Inspection Steps

### Inspect Radio Button Element

1. Right-click radio button → "Inspect Element"
2. Verify element structure (Pattern 2):
   ```html
   <label class="flex items-center p-4 border-2 border-gray-200 rounded-lg cursor-pointer">
     <input type="radio" name="groupName" value="value" x-model="variableName" class="text-blue-600 focus:ring-blue-500 w-4 h-4">
     <span class="ml-3 text-base font-medium text-gray-700">Label text</span>
   </label>
   ```
3. Verify element structure (Pattern 1):
   ```html
   <div class="radio-item">
     <input type="radio" name="groupName" value="value" x-model="variableName">
     <label>Label text</label>
   </div>
   ```
4. Check computed styles in Styles panel
5. Verify `tools-pages.css` is loaded (check Sources/Network tab)

### Check CSS Selectors

1. In Elements panel, select radio button
2. In Styles panel, search for `input[type="radio"]:checked`
3. **Expected:** Should see styles from `tools-pages.css`:
   - `border-color: #4D8EF3`
   - `background-color: #4D8EF3`
   - `::before` pseudo-element with white dot
4. Check label styles: `label:has(input[type="radio"]:checked)`
5. **Expected:** Should see label border and background color changes

### Verify Alpine.js Binding

1. In Console, run:
   ```javascript
   Alpine.$data(document.querySelector('[x-data]'))
   ```
2. Check if radio model variable exists
3. Toggle radio buttons and verify value updates
4. **Expected:** Model value should update immediately to match checked radio's `value` attribute

## Common Issues and Solutions

### Issue: Radio button doesn't show checked state visually (Pattern 2)

**Symptoms:**
- Radio button `checked` property is `true` (functional)
- Radio circle remains white/gray (visual state not updating)
- Label border/background doesn't change

**Causes:**
1. CSS file not loaded
2. Radio has `.sr-only` or `.custom-radio` class (excluded from general styles)
3. CSS `:has()` selector not supported (older browsers)
4. Browser cache issue

**Solutions:**
1. Check Network tab - verify `tools-pages.css` loads successfully
2. Verify radio doesn't have excluded classes (`.sr-only`, `.custom-radio`)
3. Check browser compatibility - `:has()` selector requires Chrome 105+, Firefox 121+, Safari 15.4+
4. Verify general radio styles exist in CSS: `input[type="radio"]:not(.sr-only):not(.custom-radio):checked`
5. Hard refresh browser (Ctrl+Shift+R / Cmd+Shift+R)
6. Clear browser cache

### Issue: Label doesn't change appearance when radio checked (Pattern 2)

**Symptoms:**
- Radio circle shows checked state correctly
- Label border/background doesn't change

**Causes:**
1. `:has()` selector not supported (older browsers)
2. CSS selector too specific
3. Label has conflicting classes

**Solutions:**
1. Check browser compatibility for `:has()` selector
2. Verify CSS selector: `label:has(input[type="radio"]:not(.sr-only):not(.custom-radio):checked)`
3. Check label doesn't have `.radio-button-compact` class (excluded from general styles)
4. Verify label structure - radio must be direct child of label

### Issue: Pattern 1 (.radio-item) radios not working

**Symptoms:**
- Radio buttons show default browser styling
- Label doesn't get blue background when checked

**Causes:**
1. CSS for `.radio-item` not loaded
2. Radio input not hidden (`display: none`)
3. Label structure incorrect

**Solutions:**
1. Verify `.radio-item input[type="radio"]` has `display: none`
2. Check `.radio-item input[type="radio"]:checked + label` styles exist
3. Verify HTML structure: radio input before label (sibling, not child)
4. Check `tools-pages.css` includes `.radio-item` styles

### Issue: Multiple radios checked in same group

**Symptoms:**
- More than one radio checked at a time
- Clicking one doesn't uncheck others

**Causes:**
1. Radios don't have same `name` attribute
2. Alpine.js `x-model` binding issue
3. JavaScript interference

**Solutions:**
1. Verify all radios in group have identical `name` attribute
2. Check `x-model` binding - should bind to same variable for all radios in group
3. Verify Alpine.js is working correctly (check console for errors)
4. Test without Alpine.js - native HTML radio behavior should work

### Issue: Radio button dot not visible

**Symptoms:**
- Radio circle turns blue when checked
- No white dot visible in center

**Causes:**
1. `::before` pseudo-element not rendering
2. Dot positioning incorrect
3. Z-index or overflow issue

**Solutions:**
1. Verify radio has `position: relative`
2. Check `::before` pseudo-element styles:
   - `content: ''` (required)
   - `position: absolute`
   - Correct `transform: translate(-50%, -50%)` for centering
   - White `background-color`
3. Check parent container doesn't have `overflow: hidden`
4. Verify dot size (`width: 0.375rem`, `height: 0.375rem`)

## Best Practices for Radio Button Implementation

### HTML Structure (Pattern 2)

```html
<!-- ✅ GOOD: Radio inside label with proper classes -->
<label class="flex items-center p-4 border-2 border-gray-200 rounded-lg cursor-pointer hover:border-blue-300 hover:bg-blue-50 transition-all duration-200">
  <input type="radio" name="groupName" value="value" x-model="variableName" class="text-blue-600 focus:ring-blue-500 w-4 h-4">
  <span class="ml-3 text-base font-medium text-gray-700">Label text</span>
</label>

<!-- ❌ BAD: Radio outside label -->
<input type="radio" name="groupName" value="value">
<span>Label text</span>
```

### HTML Structure (Pattern 1)

```html
<!-- ✅ GOOD: Radio-item pattern -->
<div class="radio-item">
  <input type="radio" name="groupName" value="value" x-model="variableName">
  <label>Label text</label>
</div>

<!-- ❌ BAD: Label wraps radio (different pattern) -->
<label class="radio-item">
  <input type="radio" name="groupName" value="value">
  Label text
</label>
```

### Alpine.js Binding

```html
<!-- ✅ GOOD: Simple x-model binding, same for all radios in group -->
<input type="radio" name="country" value="DE" x-model="selectedCountry">
<input type="radio" name="country" value="AT" x-model="selectedCountry">
<input type="radio" name="country" value="CH" x-model="selectedCountry">

<!-- ❌ BAD: Different x-model bindings for same group -->
<input type="radio" name="country" value="DE" x-model="countryDE">
<input type="radio" name="country" value="AT" x-model="countryAT">
```

### Radio Group Naming

```html
<!-- ✅ GOOD: All radios in group have same name -->
<input type="radio" name="inputType" value="netto" x-model="inputType">
<input type="radio" name="inputType" value="brutto" x-model="inputType">

<!-- ❌ BAD: Different names prevent group behavior -->
<input type="radio" name="inputType1" value="netto">
<input type="radio" name="inputType2" value="brutto">
```

## Testing Checklist

- [ ] Radio button shows checked state immediately on click (Pattern 2: blue circle, white dot, blue label border)
- [ ] Only one radio checked at a time in same group
- [ ] Previous radio unchecks when new radio is clicked
- [ ] Alpine.js model updates correctly (`x-model` binding works)
- [ ] DOM `checked` attribute syncs with Alpine.js model
- [ ] CSS visual styles apply correctly (Pattern 2: blue circle, white dot, label styling)
- [ ] Pattern 1 (`.radio-item`) radios work correctly (hidden input, styled label)
- [ ] Radio buttons work on all tools pages consistently
- [ ] Custom radio classes (`.custom-radio`, `.radio-button-compact`) not affected
- [ ] No console errors related to Alpine.js or CSS
- [ ] Radio buttons work on mobile devices (touch interaction)
- [ ] Radio buttons accessible (keyboard navigation, screen readers)
- [ ] `:has()` selector supported (modern browsers)

## Browser Compatibility

Tested and working on:
- Chrome/Edge (Chromium) 105+ - ✅ (full `:has()` support)
- Firefox 121+ - ✅ (full `:has()` support)
- Safari 15.4+ - ✅ (full `:has()` support)
- Mobile Safari (iOS 15.4+) - ✅
- Chrome Mobile (Android) - ✅

**Note:** `:has()` selector is required for Pattern 2 label styling. Older browsers will show radio checked state but label styling may not work.

## Pattern Identification

### Pattern 1: `.radio-item`
- Radio input is hidden (`display: none`)
- Label is styled and gets blue background when checked
- Used in: tools_stundenlohnrechner.php, tools_tvoed_sue.php, tools_arbeitszeitrechner.php, etc.

### Pattern 2: Direct radio in label
- Radio input is visible inside label
- Label has `border-2 border-gray-200 rounded-lg` styling
- Used in: tools_mehrwertsteuer_rechner.php, tools_arbeitstage_rechner.php

### Pattern 3: Custom classes
- `.custom-radio` - tools_paypal_gebuhrenrechner.php (has own CSS)
- `.radio-button-compact` - tools_midijob_rechner.php (has own CSS with `:has()`)

## Related Documentation

- `.cursor/rules/tools-pages.mdc` - Tools page patterns and radio button styling
- `v2/css/tools-pages.css` - Radio button CSS implementation
- Alpine.js documentation: https://alpinejs.dev/directives/model
- MDN `:has()` selector: https://developer.mozilla.org/en-US/docs/Web/CSS/:has

