Blog

2025-07-20ยทreact

Creating Responsive Dialog and Drawer Components with shadcn/ui

Taher Hathi

Taher Hathi avatar

Taher Hathi

Learn how to build adaptive modal components that transform from dialogs on desktop to drawers on mobile for optimal user experience.

Cover image

Creating responsive modal components that adapt to different screen sizes is crucial for modern web applications. While desktop users prefer centered dialogs, mobile users benefit from drawer-style interfaces that slide up from the bottom. This article shows how to build a unified component that seamlessly transitions between these two patterns.

The Challenge with Traditional Modals

Standard dialog components work well on desktop but can feel cramped and awkward on mobile devices. The small screen real estate makes centered modals difficult to interact with, especially when they contain forms or lengthy content. Users often struggle with:

  • Limited viewport space being consumed by the modal
  • Difficulty reaching close buttons in corner positions
  • Poor thumb accessibility on larger phones
  • Awkward scrolling within constrained modal heights

Building the Adaptive Solution

Our approach uses a single component that detects screen size and renders appropriately. The component leverages Radix UI primitives for accessibility while applying different styling patterns based on device capabilities.

Key Features

The responsive dialog/drawer component includes several thoughtful design decisions:

Mobile-First Drawer Experience

  • Slides up from the bottom for natural thumb interaction
  • Includes a visual drag handle for intuitive gesture recognition
  • Maximizes content area while maintaining familiar mobile patterns
  • Positions close button in easily reachable locations

Desktop Dialog Behavior

  • Centers content with appropriate sizing constraints
  • Maintains traditional modal interaction patterns
  • Provides subtle animations that feel polished
  • Uses backdrop blur effects for modern visual appeal

Consistent Styling Across Breakpoints

  • Unified color scheme that adapts to light and dark modes
  • Smooth transitions between mobile and desktop layouts
  • Accessible focus management regardless of presentation style
  • Proper ARIA labeling for screen readers

Implementation Details

The component uses a custom hook to detect mobile screens and conditionally renders different layouts. Here's how the magic happens:

Device Detection Strategy

1const isMobile = useIsMobile();

This hook determines whether to show the drawer or dialog version, typically checking for screen widths below tablet breakpoints.

Mobile Drawer Layout

For mobile devices, the component renders at the bottom of the screen with:

  • Rounded top corners for visual polish
  • A drag handle indicator for gesture hints
  • Slide-up animations that feel natural
  • Full-width content area maximization

The mobile version uses these key styling patterns:

1/* Bottom positioning with slide animations */
2fixed inset-x-0 bottom-0
3/* Rounded top corners only */
4rounded-t-[10px]
5/* Slide animation classes */
6data-[state=open]:slide-in-from-bottom

Desktop Dialog Experience

Desktop users receive a traditional centered modal with:

  • Centered positioning with maximum width constraints
  • Subtle zoom and fade animations
  • Backdrop blur effects for modern aesthetics
  • Optimal focus management

The desktop styling emphasizes:

1/* Centered positioning */
2left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%]
3/* Maximum width constraints */
4w-full max-w-lg
5/* Refined animations */
6data-[state=open]:zoom-in-95

Enhanced User Experience Benefits

This adaptive approach delivers significant UX improvements:

Mobile Users Benefit From

  • Larger interaction targets that work well with touch
  • Content that doesn't compete with virtual keyboards
  • Familiar bottom-sheet patterns from native mobile apps
  • Gesture-friendly close mechanisms

Desktop Users Enjoy

  • Focused content that doesn't dominate the entire screen
  • Precise mouse interaction with appropriately sized targets
  • Professional appearance that matches desktop software conventions
  • Keyboard navigation that follows expected patterns

Accessibility Considerations

The component maintains accessibility across both presentations:

  • Proper focus trapping keeps keyboard users within the modal content
  • ARIA labels provide context for screen readers
  • High contrast ratios ensure visibility in both light and dark themes
  • Keyboard shortcuts work consistently across device types
  • Focus management returns users to appropriate trigger elements on close

Complete Implementation Code

Here's the full implementation of the responsive dialog/drawer component:

1"use client";
2
3import * as React from "react";
4import * as DialogPrimitive from "@radix-ui/react-dialog";
5import { X } from "lucide-react";
6
7import { cn } from "@/lib/utils";
8import { useIsMobile } from "@/hooks/use-mobile";
9
10const Dialog = DialogPrimitive.Root;

Integration and Usage

Using the component requires minimal changes to existing code:

1<Dialog>
2  <DialogTrigger>Open Modal</DialogTrigger>
3  <DialogContent>
4    <DialogHeader>
5      <DialogTitle>Responsive Modal</DialogTitle>
6      <DialogDescription>
7        This modal adapts to your screen size automatically.
8      </DialogDescription>
9    </DialogHeader>
10    

The component automatically detects screen size and applies appropriate styling without requiring additional props or configuration.

Performance and Bundle Considerations

The implementation adds minimal overhead while delivering maximum flexibility:

  • Single component reduces bundle size compared to separate dialog/drawer libraries
  • Conditional rendering prevents unnecessary DOM elements
  • Efficient CSS classes minimize runtime style calculations
  • Shared Radix primitives reduce overall dependency weight

Customization Options

The component supports extensive customization while maintaining responsive behavior:

Styling Flexibility

  • Tailwind classes can be overridden through className props
  • Custom animations can replace defaults
  • Brand colors integrate seamlessly through CSS custom properties
  • Spacing and sizing adapt to design system requirements

Behavioral Modifications

  • Breakpoint thresholds can be adjusted for specific use cases
  • Animation durations and easing can be customized
  • Close behavior can be modified for different interaction patterns
  • Content scrolling can be configured per device type

Best Practices and Recommendations

When implementing responsive modals, consider these guidelines:

Content Strategy

  • Keep mobile content concise and scannable
  • Use progressive disclosure for complex forms
  • Prioritize primary actions in easily reachable locations
  • Test with actual devices rather than browser responsive modes

Performance Optimization

  • Lazy load modal content when possible
  • Implement proper cleanup for animation listeners
  • Consider preloading critical modal assets
  • Monitor bundle size impact of responsive components

Testing Approaches

  • Verify behavior across multiple device categories
  • Test with various screen orientations
  • Validate accessibility with assistive technologies
  • Check performance impact on lower-end devices

Conclusion

Responsive dialog and drawer components represent a significant improvement over traditional one-size-fits-all modals. By adapting presentation to device capabilities, we create more intuitive and accessible user experiences. The implementation combines modern React patterns with thoughtful UX design to deliver components that feel native on every device.

This approach demonstrates how thoughtful component design can eliminate the need for separate mobile and desktop implementations while actually improving the user experience on both platforms. As responsive design continues evolving, components like this show the path toward truly adaptive user interfaces that work seamlessly across the full spectrum of modern devices.

Share this post

Creating Responsive Dialog and Drawer Components with shadcn/ui | Nextjsshop Blog