Menu

Tailwind CSS Resize

Resize allows elements to be resizable by the user- horizontally, vertically, or both. It typically controls how an element can be dragged or stretched by the end-user, often seen in text areas or other containers.

Tailwind includes a set of utilities that map directly to resize properties, making it easy to apply these transformations in a production-ready environment. Throughout this guide, we will explore how to utilize these utilities in different contexts, showcase how to manage them during interactive states, and introduce ways to adapt them for responsive design.

ClassPropertiesExample
resize-noneresize: none;<div className="resize-none"></div>
resize-yresize: vertical;<div className="resize-y"></div>
resize-xresize: horizontal;<div className="resize-x"></div>
resizeresize: both;<div className="resize"></div>

Overview of Resize

All Directions Resizing

Allowing an element to be resized in both height and width can significantly improve the flexibility of your layout. This approach is often used in text editing environments, multi-line input fields, or other scenarios where you anticipate unpredictable content lengths.

This is a live editor. Play around with it!
export default function BothDirections() {
  return (
    <div className="h-screen w-screen p-8 bg-gradient-to-r from-green-100 to-blue-100 flex items-center justify-center">
      <div className="resize overflow-auto border-2 border-green-500 bg-white p-4 shadow-lg">
        {/* resize => resize: both; */}
        <img 
          src="https://images.unsplash.com/photo-1527443224154-c4a3942d3acf"
          alt="All directions resizing"
          className="object-cover w-full h-64 rounded"
        />
        <div className="mt-4 text-gray-700">
          Feel free to drag the edges of this component in both width and height.
        </div>
      </div>
    </div>
  );
}

Vertically Resizing

Restricting resizing to a vertical direction is beneficial if your container should only expand in height. This is frequently used for textareas where the text length varies but the element’s width remains consistent to match form layouts or other page structures.

This is a live editor. Play around with it!
export default function VerticalOnly() {
  return (
    <div className="h-screen w-screen flex items-center justify-center bg-gray-200 p-8">
      <textarea
        className="resize-y border border-blue-500 bg-white p-4 rounded w-96"
        /* resize-y => resize: vertical; */
        rows={4}
        placeholder="Only vertical resizing is allowed here..."
      />
    </div>
  );
}

Horizontally Resizing

Some use cases demand a horizontally resizable container—for instance, a sidebar that you want users to be able to expand or contract, but maintain fixed height constraints. This approach is equally relevant for advanced layouts, such as adjustable columns in data tables.

This is a live editor. Play around with it!
export default function HorizontalOnly() {
  return (
    <div className="h-screen w-screen flex items-center justify-center bg-gray-200 p-8">
      <textarea
        className="resize-x border border-blue-500 bg-white p-4 rounded w-32 h-60"
        /* resize-x => resize: horizonta; */
        rows={4}
        placeholder="Only horizontal resizing is allowed here..."
      />
    </div>
  );
}

No Resizing

Sometimes you need to ensure that an element cannot be resized, effectively disabling the user’s ability to modify its dimensions. Even if default styling might allow resizing (e.g., <textarea> in some browsers), you can override it with a straightforward utility in Tailwind.

This is a live editor. Play around with it!
export default function NoResize() {
  return (
    <div className="h-screen w-screen flex items-center justify-center bg-gray-50">
      <textarea
        className="resize-none border border-red-400 p-4 w-80 h-32"
        /* resize-none => resize: none; */
        placeholder="Resizing has been disabled for this field..."
      />
    </div>
  );
}

States and Responsiveness

While we have covered core functionality, styling often needs to adapt based on state changes (like a hover or focus event), and also across different breakpoints. This flexibility ensures that your design remains consistent yet adaptable, especially for complex, interactive UI elements.

Hover and Focus States

Using state modifiers for hover and focus states can emphasize the resizable container when the user interacts with it.

This is a live editor. Play around with it!
export default function StatesEnhancement() {
  return (
    <div className="h-screen w-screen flex items-center justify-center bg-gray-50">
      <textarea
        className="resize-none hover:resize border border-red-400 p-4 w-80 h-32"
        /* resize-none => resize: none;
           On hover-> resize => resize: both;
         */
        placeholder="Resizing is enabled on hover..."
      />
    </div>
  );
}

Breakpoint Modifiers

Breakpoint modifiers in Tailwind allow you to override classes at specific screen widths. For example, you might want to enable horizontal resizing on large screens but disable it on smaller devices to preserve layout integrity.

This is a live editor. Play around with it!
export default function ResponsiveResize() {
  return (
    <div className="h-screen w-screen flex items-center justify-center bg-gray-50">
      { /* lg:resize-x => resize: horizontal for large screens; */}
      <textarea
        className="resize-none lg:resize border border-red-400 p-4 w-80 h-32"
        placeholder="Resizing is enabled only on large screens..."
      />
    </div>
  );
}

Real World Examples

Dynamic Text Editor with Resize Controls

A text editor component with resizable input area and character count display.

This is a live editor. Play around with it!
export default function TextEditor() {
  const initialText = [
    {
      id: 1,
      placeholder: "Start writing your story...",
      savedContent: "Lorem ipsum dolor sit amet, consectetur adipiscing elit..."
    }
  ];

  return (
    <div className="p-6 bg-gray-50">
      <div className="max-w-3xl mx-auto bg-white rounded-lg shadow-lg p-4">
        <textarea
          className="w-full p-4 border rounded-md resize-y min-h-[200px] max-h-[600px]"
          placeholder={initialText[0].placeholder}
          defaultValue={initialText[0].savedContent}
        />
        <div className="mt-2 text-sm text-gray-500 flex justify-between">
          <span>Character count: {initialText[0].savedContent.length}</span>
          <span>Drag bottom edge to resize</span>
        </div>
      </div>
    </div>
  );
}

A responsive product gallery with resizable image containers.

This is a live editor. Play around with it!
export default function ProductGallery() {
  const products = [
    {
      id: 1,
      name: "Premium Leather Wallet",
      price: "$89.99",
      src: "https://images.unsplash.com/photo-1627123424574-724758594e93",
      alt: "Brown leather wallet"
    },
    {
      id: 2,
      name: "Vintage Watch",
      price: "$299.99",
      src: "https://images.unsplash.com/photo-1524592094714-0f0654e20314",
      alt: "Classic analog watch"
    },
    {
      id: 3,
      name: "Designer Sunglasses",
      price: "$159.99",
      src: "https://images.unsplash.com/photo-1572635196237-14b3f281503f",
      alt: "Fashionable sunglasses"
    },
    {
      id: 4,
      name: "Canvas Backpack",
      price: "$129.99",
      src: "https://images.unsplash.com/photo-1553062407-98eeb64c6a62",
      alt: "Durable canvas backpack"
    },
    {
      id: 5,
      name: "Silver Necklace",
      price: "$199.99",
      src: "https://images.unsplash.com/photo-1515562141207-7a88fb7ce338",
      alt: "Sterling silver necklace"
    },
  ];

  return (
    <div className="p-8 bg-gray-100">
      <div className="grid grid-cols-1 gap-6">
        {products.map((product) => (
          <div key={product.id} className="bg-white rounded-lg overflow-hidden shadow-md">
            <div className="resize-y min-h-[200px] max-h-[400px] overflow-hidden">
              <img
                src={product.src}
                alt={product.alt}
                className="w-full h-full object-cover"
              />
            </div>
            <div className="p-4">
              <h3 className="font-semibold">{product.name}</h3>
              <p className="text-blue-600">{product.price}</p>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

Reviews Dashboard

A resizable textarea component for customer service representatives to manage product reviews.

This is a live editor. Play around with it!
const ReviewsDashboard = () => {
  const data = [
    {
      id: 1,
      product: "Wireless Headphones",
      customer: "Emily Parker",
      rating: 4,
      review: "Great sound quality but battery life could be better",
      response: "Thank you for your feedback about the battery life.",
      image: "https://images.unsplash.com/photo-1505740420928-5e560c06d30e"
    },
    {
      id: 2,
      product: "Smart Watch",
      customer: "Michael Chen",
      rating: 5,
      review: "Perfect fitness companion!",
      response: "We're glad you're enjoying the fitness features!",
      image: "https://images.unsplash.com/photo-1523275335684-37898b6baf30"
    },
    {
      id: 3,
      product: "Laptop Stand",
      customer: "Sarah Johnson",
      rating: 3,
      review: "Good build quality but could be more adjustable",
      response: "",
      image: "https://images.unsplash.com/photo-1527864550417-7fd91fc51a46"
    },
    {
      id: 4,
      product: "Wireless Mouse",
      customer: "David Wilson",
      rating: 5,
      review: "Exactly what I needed for my work setup",
      response: "",
      image: "https://images.unsplash.com/photo-1615663245857-ac93bb7c39e7"
    },
    {
      id: 5,
      product: "Mechanical Keyboard",
      customer: "Lisa Zhang",
      rating: 4,
      review: "Love the tactile feedback, slightly loud though",
      response: "",
      image: "https://images.unsplash.com/photo-1511467687858-23d96c32e4ae"
    },
    {
      id: 6,
      product: "USB-C Hub",
      customer: "Robert Brown",
      rating: 4,
      review: "Great connectivity options, runs a bit warm",
      response: "",
      image: "https://images.unsplash.com/photo-1544244015-0df4b3ffc6b0"
    }
  ];

  return (
    <div className="p-6 max-w-6xl mx-auto">
      <h1 className="text-2xl font-bold mb-6">Customer Reviews Dashboard</h1>
      <div className="grid gap-6">
        {data.map((item) => (
          <div key={item.id} className="bg-white p-4 rounded-lg shadow">
            <div className="flex items-start gap-4">
              <img 
                src={item.image} 
                alt={item.product}
                className="w-24 h-24 object-cover rounded"
              />
              <div className="flex-1">
                <h3 className="font-semibold">{item.product}</h3>
                <div className="text-sm text-gray-600 mb-2">
                  Customer: {item.customer} | Rating: {item.rating}/5
                </div>
                <p className="text-gray-800 mb-3">{item.review}</p>
                <textarea
                  className="w-full p-2 border rounded resize-y min-h-[100px] focus:ring-2 focus:ring-blue-500"
                  placeholder="Write your response..."
                  defaultValue={item.response}
                />
              </div>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
};

export default ReviewsDashboard;

Notes Application

A note-taking interface with resizable text areas for each note, allowing users to adjust the height based on content length.

This is a live editor. Play around with it!
const NotesApp = () => {
  const data = [
    {
      id: 1,
      title: "Project Ideas",
      content: `1. Build a recipe app
2. Create a budget tracker
3. Design a portfolio website`,
      category: "Work",
      color: "bg-blue-100",
      icon: "https://images.unsplash.com/photo-1512314889357-e157c22f938d"
    },
    {
      id: 2,
      title: "Meeting Notes",
      content: `Discuss Q2 goals
Review team performance
Plan upcoming sprint`,
      category: "Work",
      color: "bg-yellow-100",
      icon: "https://images.unsplash.com/photo-1517245386807-bb43f82c33c4"
    },
    {
      id: 3,
      title: "Book Recommendations",
      content: `1. The Pragmatic Programmer
2. Clean Code
3. Design Patterns`,
      category: "Learning",
      color: "bg-purple-100",
      icon: "https://images.unsplash.com/photo-1544716278-ca5e3f4abd8c"
    },
    {
      id: 4,
      title: "Workout Plan",
      content: `Monday: Upper body
Wednesday: Lower body
Friday: Cardio`,
      category: "Health",
      color: "bg-red-100",
      icon: "https://images.unsplash.com/photo-1517836357463-d25dfeac3438"
    },
    {
      id: 5,
      title: "Travel Plans",
      content: `Research destinations
Check flight prices
Plan itinerary`,
      category: "Personal",
      color: "bg-indigo-100",
      icon: "https://images.unsplash.com/photo-1488646953014-85cb44e25828"
    }
  ];

  return (
    <div className="min-h-screen bg-gray-50 p-8">
      <div className="max-w-7xl mx-auto">
        <div className="flex justify-between items-center mb-8">
          <h1 className="text-3xl font-bold">My Notes</h1>
          <div className="flex gap-4">
            <select className="px-4 py-2 rounded border">
              <option>All Categories</option>
              <option>Work</option>
              <option>Personal</option>
              <option>Learning</option>
              <option>Health</option>
            </select>
            <button className="px-4 py-2 bg-blue-600 text-white rounded">
              New Note
            </button>
          </div>
        </div>

        <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
          {data.map((note) => (
            <div key={note.id} className={`${note.color} rounded-lg p-6 shadow-sm`}>
              <div className="flex items-center gap-3 mb-4">
                <img 
                  src={note.icon} 
                  alt={note.category}
                  className="w-8 h-8 rounded"
                />
                <div>
                  <h3 className="font-semibold">{note.title}</h3>
                  <span className="text-sm text-gray-600">{note.category}</span>
                </div>
              </div>
              <textarea
                className="w-full bg-white/50 rounded p-3 resize-y min-h-[120px] focus:ring-2 focus:ring-blue-500"
                defaultValue={note.content}
              />
              <div className="flex justify-end mt-4 gap-2">
                <button className="text-gray-600 hover:text-gray-900">
                  Edit
                </button>
                <button className="text-red-600 hover:text-red-900">
                  Delete
                </button>
              </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
};

export default NotesApp;

Chat Application

A modern chat interface with resizable message input area.

This is a live editor. Play around with it!
const ChatApp = () => {
  const data = [
    {
      id: 1,
      name: "Alice Cooper",
      avatar: "https://images.unsplash.com/photo-1494790108377-be9c29b29330",
      status: "online",
      lastMessage: "Hey, are we still meeting today?",
      time: "2:30 PM",
      unread: 2
    },
    {
      id: 2,
      name: "Bob Wilson",
      avatar: "https://images.unsplash.com/photo-1500648767791-00dcc994a43e",
      status: "offline",
      lastMessage: "Thanks for the update!",
      time: "Yesterday",
      unread: 0
    },
    {
      id: 3,
      name: "Carol Martinez",
      avatar: "https://images.unsplash.com/photo-1438761681033-6461ffad8d80",
      status: "online",
      lastMessage: "The project files are ready for review",
      time: "9:15 AM",
      unread: 1
    },
    {
      id: 4,
      name: "David Chang",
      avatar: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d",
      status: "busy",
      lastMessage: "Let's schedule a call next week",
      time: "Tuesday",
      unread: 0
    },
    {
      id: 5,
      name: "Eva Green",
      avatar: "https://images.unsplash.com/photo-1438761681033-6461ffad8d80",
      status: "online",
      lastMessage: "Perfect, I'll take care of it",
      time: "Monday",
      unread: 0
    },
    {
      id: 6,
      name: "Frank Johnson",
      avatar: "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e",
      status: "offline",
      lastMessage: "How about the budget report?",
      time: "Last week",
      unread: 0
    }
  ];

  return (
    <div className="h-screen flex flex-col sm:flex-row bg-gray-100">
      {/* Sidebar - Full width on mobile, side panel on desktop */}
      <div className="w-full sm:w-80 bg-white border-b sm:border-r sm:min-h-screen">
        <div className="p-3 sm:p-4">
          <div className="flex items-center justify-between mb-4">
            <h2 className="text-lg font-bold">Messages</h2>
            <button className="p-1.5 hover:bg-gray-100 rounded-full text-blue-600">
              <span className="text-xl">+</span>
            </button>
          </div>
          
          <div className="space-y-1">
            {data.map((chat) => (
              <div
                key={chat.id}
                className="flex items-center gap-2 p-2 hover:bg-gray-50 rounded-lg cursor-pointer"
              >
                <div className="relative flex-shrink-0">
                  <img
                    src={chat.avatar}
                    alt={chat.name}
                    className="w-10 h-10 rounded-full object-cover"
                  />
                  <span
                    className={`absolute bottom-0 right-0 w-2.5 h-2.5 rounded-full border-2 border-white
                      ${chat.status === 'online' ? 'bg-green-500' : 
                        chat.status === 'busy' ? 'bg-red-500' : 'bg-gray-500'}`}
                  />
                </div>
                <div className="flex-1 min-w-0">
                  <div className="flex justify-between items-baseline">
                    <h3 className="font-medium text-sm truncate">{chat.name}</h3>
                    <span className="text-xs text-gray-500 ml-1 flex-shrink-0">{chat.time}</span>
                  </div>
                  <p className="text-xs text-gray-600 truncate">{chat.lastMessage}</p>
                </div>
                {chat.unread > 0 && (
                  <span className="bg-blue-500 text-white text-xs w-5 h-5 flex items-center justify-center rounded-full flex-shrink-0">
                    {chat.unread}
                  </span>
                )}
              </div>
            ))}
          </div>
        </div>
      </div>

      {/* Main Chat Area */}
      <div className="flex-1 flex flex-col min-w-0">
        {/* Chat Header */}
        <div className="bg-white border-b p-3">
          <div className="flex items-center gap-2">
            <img
              src={data[0].avatar}
              alt={data[0].name}
              className="w-8 h-8 rounded-full"
            />
            <div className="min-w-0">
              <h3 className="font-medium text-sm truncate">{data[0].name}</h3>
              <span className="text-xs text-green-500">Online</span>
            </div>
          </div>
        </div>

        {/* Messages Area */}
        <div className="flex-1 overflow-y-auto p-3">
          {/* Message bubbles would go here */}
        </div>

        {/* Message Input */}
        <div className="sticky bottom-0 bg-white border-t p-2 sm:p-3">
          <textarea
            className="w-full p-2.5 text-sm border rounded-lg resize-y min-h-[44px] max-h-[160px] focus:ring-2 focus:ring-blue-500 focus:border-blue-500 mb-2"
            placeholder="Type your message..."
            aria-label="Message input"
            style={{ lineHeight: '1.2' }}
          />
          <div className="flex items-center justify-between">
            <div className="flex items-center gap-1.5">
              <button 
                className="p-2 hover:bg-gray-100 rounded-full text-gray-600"
                aria-label="Attach file"
              >
                📎
              </button>
              <button 
                className="p-2 hover:bg-gray-100 rounded-full text-gray-600"
                aria-label="Add emoji"
              >
                😊
              </button>
            </div>
            <button 
              className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
              aria-label="Send message"
            >
              Send
            </button>
          </div>
        </div>
      </div>
    </div>
  );
};

export default ChatApp;

Best Practices

Leverage Utility Combinations

Tailwind's utility classes can be combined thoughtfully for sophisticated styling. Pairing resize utilities with padding, border, or background classes ensures a resizable element remains visually appealing. For instance, you might use resize-y with border, rounded corners, and hover effects to create an engaging, modern input field that clearly signals its interactivity.

Combining multiple utilities lets you unify your brand’s design language. By systematically layering classes, you can quickly build components that integrate resizing, spacing, color interactions, and typography without reverting to heavy custom styles.

Build Responsive Design

Responsive design ensures that resizing remains meaningful across a broad range of devices and screen sizes. Tailwind’s breakpoint modifiers, such as md, lg, etc., let you toggle resizing behavior based on screen width. A container may allow two-dimensional scaling only on desktops, while restricting it entirely on small mobile screens to preserve layout stability.

The key is to identify where resizing enhances usability for your target audience. On smaller touchscreens, pinch-zoom might be more intuitive than dragging edges. Meanwhile, mid-sized tablets or laptops can benefit from partial resizing to accommodate content. By tailoring each breakpoint setting, you can deliver a more intuitive experience.

Accessibility Considerations

Enhance Readability and Navigability

Resizing in Tailwind can greatly enhance readability, particularly for users who need to enlarge text or interface elements for better accessibility. The ability to drag the element size ensures that content remains well-structured, prevents overflow or clipping, and supports better comprehension.

Additionally, thoughtfully selected font families, weights, and sizes play a vital role in creating a comfortable reading experience. Navigability is just as crucial—while expandable or contractible containers offer layout flexibility, they should be designed to avoid visual confusion or overlapping with nearby elements, ensuring a user-friendly interface.

Focus on High Contrast

High contrast in resizable input fields is vital for accessibility and user clarity, ensuring that users can easily distinguish interactive elements from the surrounding content. This not only supports users with low vision or color blindness but also guarantees that form elements remain easily identifiable, even when resized.

To achieve these accessibility standards, it's crucial to select color pairings that meet or exceed the WCAG contrast ratio of 4.5:1. Tailwind CSS provides a large color palette and also offers a configuration file where you can define and extend your color palette to ensure compliance with accessibility guidelines.