Skip to content

fix: prevent accordion from clipping focus rings#583

Open
niklasbartsch wants to merge 2 commits intonank1ro:mainfrom
niklasbartsch:fix/accordion-clips-focus-ring
Open

fix: prevent accordion from clipping focus rings#583
niklasbartsch wants to merge 2 commits intonank1ro:mainfrom
niklasbartsch:fix/accordion-clips-focus-ring

Conversation

@niklasbartsch
Copy link

@niklasbartsch niklasbartsch commented Jan 9, 2026

Summary

  • Added clipBehavior parameter to SizeEffect class with custom _ShadSizeTransition widget
  • Added clipBehavior parameter to ShadAccordionItem and ShadAccordionTheme
  • Default to Clip.none in accordion to prevent focus ring clipping

Root Cause

The ShadAccordionItem uses SizeTransition for the expand/collapse animation. SizeTransition internally uses ClipRect which clips any content that overflows the bounds - including focus rings that extend slightly beyond the widget's boundary.

Solution

Created a custom _ShadSizeTransition widget that supports configurable clipBehavior. When set to Clip.none, it skips the ClipRect entirely, allowing focus rings and other content to extend beyond the widget's boundary.

Test plan

  1. Place a ShadInputFormField inside a ShadAccordionItem
  2. Expand the accordion
  3. Focus the input field
  4. Verify focus ring is fully visible (not clipped)

Fixes #582

Summary by CodeRabbit

  • New Features
    • Accordion items and theme now support configurable clipping for size transitions, letting content (e.g., focus rings) extend beyond bounds when desired.
  • Bug Fixes
    • Prevents accidental clipping of focus rings and other interactive visuals during accordion animations.
  • Chores
    • Size transition component made public to allow custom, configurable clipping behaviors.

✏️ Tip: You can customize this high-level summary in your review settings.

Add clipBehavior parameter to SizeEffect and ShadAccordionItem to control
clipping behavior during size transition animations.

- Add clipBehavior parameter to SizeEffect class with custom _ShadSizeTransition
- Add clipBehavior parameter to ShadAccordionItem and ShadAccordionTheme
- Default to Clip.none in accordion to prevent focus ring clipping

Fixes nank1ro#582
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 9, 2026

Walkthrough

Adds a nullable clipBehavior property to ShadAccordionItem and ShadAccordionTheme, threads it through theme/utility code, and uses it in the size animation by making the size-transition respect the configured clip behavior (via a new public ShadSizeTransition), preventing unwanted clipping (e.g., focus rings).

Changes

Cohort / File(s) Summary
Accordion Item
lib/src/components/accordion.dart
Added final Clip? clipBehavior and constructor param; computes effectiveClipBehavior (widget → theme → default) and passes it to the size animation.
Theme
lib/src/theme/components/accordion.dart, lib/src/theme/components/accordion.g.theme.dart
Added final Clip? clipBehavior to ShadAccordionTheme; updated constructor, copyWith, merge, lerp, ==, and hashCode to include clipBehavior.
Animation Effects
lib/src/utils/effects.dart
SizeEffect now accepts Clip clipBehavior (default Clip.hardEdge) and exposes it; introduced public ShadSizeTransition (AnimatedWidget) that optionally wraps child in ClipRect unless Clip.none, and uses heightFactor alignment for the size animation.
Examples & Changelog
example/lib/pages/accordion.dart, CHANGELOG.md, pubspec.yaml
Example demonstrates toggling clipBehavior and ShadInput focus-ring case; bumped package version and added changelog entry.

Sequence Diagram(s)

(omitted — change is primarily a focused bug fix to clipping and does not introduce a multi-component control-flow that benefits from a sequence diagram)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰
A ring that peeked, then met the seam,
Now hops out bright, no clipped-off gleam.
I nudged the clip, let edges play —
The accordion smiles, let focus stay. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive The description clearly explains the problem, solution, and test plan. However, the pre-launch checklist is not filled out as required by the template. Complete the pre-launch checklist to confirm all requirements (contributor guide, tests, documentation, version bump, CHANGELOG) were followed.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main fix: preventing accordion from clipping focus rings by adding clipBehavior support.
Linked Issues check ✅ Passed The PR fully addresses issue #582 by adding clipBehavior parameter to ShadAccordionItem and ShadAccordionTheme, and implementing custom ShadSizeTransition to prevent focus ring clipping.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the focus ring clipping issue. The example updates and version bump are appropriate supporting changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@niklasbartsch
Copy link
Author

Before:
Screenshot 2026-01-09 at 12 07 03

after:
Screenshot 2026-01-09 at 12 07 08

coderabbitai[bot]
coderabbitai bot previously approved these changes Jan 9, 2026
Copy link
Owner

@nank1ro nank1ro left a comment

Choose a reason for hiding this comment

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

Update the pubspec and the CHANGELOG to be ready to deploy it, thanks for the PR 🙏

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
lib/src/utils/effects.dart (1)

46-84: Consider adding axis and alignment parameters for flexibility.

The current implementation hardcodes vertical sizing (heightFactor) and top-start alignment. Flutter's SizeTransition supports configurable axis and axisAlignment. While the current implementation works well for the accordion use case, adding these parameters would make ShadSizeTransition more reusable for other scenarios.

✨ Optional enhancement for axis/alignment support

Consider extending the implementation to support both horizontal and vertical sizing:

 class ShadSizeTransition extends AnimatedWidget {
   const ShadSizeTransition({
     super.key,
     required Animation<double> sizeFactor,
     this.clipBehavior = Clip.hardEdge,
+    this.axis = Axis.vertical,
+    this.axisAlignment = 0.0,
     this.child,
   }) : super(listenable: sizeFactor);

   final Clip clipBehavior;
+  final Axis axis;
+  final double axisAlignment;
   final Widget? child;

   Animation<double> get sizeFactor => listenable as Animation<double>;

   @override
   Widget build(BuildContext context) {
+    final alignment = axis == Axis.vertical
+        ? AlignmentDirectional(0.0, axisAlignment)
+        : AlignmentDirectional(axisAlignment, 0.0);
+    
     final result = Align(
-      alignment: AlignmentDirectional.topStart,
+      alignment: alignment,
-      heightFactor: sizeFactor.value,
+      heightFactor: axis == Axis.vertical ? sizeFactor.value : null,
+      widthFactor: axis == Axis.horizontal ? sizeFactor.value : null,
       child: child,
     );

     if (clipBehavior == Clip.none) {
       return result;
     }

     return ClipRect(
       clipBehavior: clipBehavior,
       child: result,
     );
   }
 }
example/lib/pages/accordion.dart (1)

23-26: LGTM! Effective test case for the focus ring fix.

The test implementation correctly demonstrates the issue and the fix. The toggle allows users to compare the old buggy behavior (clipping enabled) with the new correct behavior (clipping disabled).

The label "Clip content (old bug)" could be slightly clearer. Consider something like "Enable clipping (reproduces #582)" to make it more obvious that turning it ON reproduces the bug, while OFF shows the fix.

Also applies to: 39-39, 49-60, 82-86

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 778aabc and a3e7a96.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • example/lib/pages/accordion.dart
  • lib/src/utils/effects.dart
  • pubspec.yaml
✅ Files skipped from review due to trivial changes (1)
  • pubspec.yaml
🔇 Additional comments (3)
CHANGELOG.md (1)

1-5: LGTM! Clear and accurate changelog entry.

The changelog properly documents both the bug fix and the new public API surface. The entries are well-formatted and provide sufficient context for users.

lib/src/utils/effects.dart (2)

14-14: LGTM! Well-documented clipBehavior parameter.

The clipBehavior parameter with default Clip.hardEdge maintains backward compatibility while enabling the fix. The documentation clearly explains the purpose and usage.

Also applies to: 20-26


35-39: LGTM! Proper integration with the new ShadSizeTransition.

The refactoring to use ShadSizeTransition with the clipBehavior parameter correctly implements the solution for preventing focus ring clipping.

@niklasbartsch niklasbartsch requested a review from nank1ro January 12, 2026 09:47
@nank1ro
Copy link
Owner

nank1ro commented Jan 12, 2026

bug.mov

@niklasbartsch When clip is none, the item of the accordion animates above the title, and it is not a good thing.

@nank1ro
Copy link
Owner

nank1ro commented Mar 2, 2026

@niklasbartsch did you have time to check my last comment?

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.

ShadAccordion clips focus ring of child widgets

2 participants