Container Component: Inspired from Shadcn and Tailwind UI
I've been working with shadcn/ui for a while now, and there's something that always felt missing—a proper container component. You know, the kind that handles responsive layouts elegantly without you having to think about it every time.
The Problem I Kept Running Into
Every project needs containers. Whether you're building a landing page or a complex dashboard, you're constantly wrapping content in divs with max-w-7xl mx-auto px-4 sm:px-6 lg:px-8
. It works, but it's repetitive and error-prone. I found myself copying the same patterns from Tailwind UI examples, tweaking padding and max-widths project after project.
Learning from Tailwind UI's Approach
Tailwind UI has this really thoughtful approach to containers. They don't just slap a container
class on everything. Instead, they use specific patterns:
- Full-width on mobile, constrained above
- Always constrained with consistent padding
- Breakpoint-specific constraints
- Narrow layouts for content-heavy pages
Each pattern serves a real purpose. The "full-width on mobile" approach, for example, maximizes screen real estate on small devices while providing comfortable reading widths on larger screens.
Building the Component
I experimented with class-variance-authority to handle the different layout patterns cleanly. The key insight was that each variant needs its own padding strategy—some start padding at sm:
, others include mobile padding from the start.
Installation
Option 1: Install via Registry (Recommended)
bunx shadcn@latest add https://registry.emreturan.dev/r/container.json
This will automatically install the component and its dependencies to your project.
Option 2: Manual Installation
Copy and paste the following code into your project:
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const containerVariants = cva("mx-auto", {
variants: {
variant: {
fullMobileConstrainedPadded: "max-w-7xl sm:px-6 lg:px-8",
constrainedPadded: "max-w-7xl px-4 sm:px-6 lg:px-8",
fullMobileConstrainedBreakpointPadded: "max-w-screen-xl sm:px-6 lg:px-8",
constrainedBreakpointPadded: "max-w-screen-xl px-4 sm:px-6 lg:px-8",
narrowConstrainedPadded: "max-w-3xl px-4 sm:px-6 lg:px-8",
},
},
defaultVariants: {
variant: "narrowConstrainedPadded",
},
})
export interface ContainerProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof containerVariants> {}
const Container = React.forwardRef<HTMLDivElement, ContainerProps>(
({ className, children, variant, ...props }, ref) => {
return (
<div ref={ref} className={cn(containerVariants({ variant }), className)} {...props}>
{children}
</div>
)
},
)
Container.displayName = "Container"
export { Container, containerVariants }
Usage Examples
Here's how I typically use it:
// For blog posts and articles
<Container variant="narrowConstrainedPadded">
<article>Your content here</article>
</Container>
// For full-width mobile, constrained desktop
<Container variant="fullMobileConstrainedPadded">
<header>Your header content</header>
</Container>
Each variant serves a specific layout need. The naming follows Tailwind UI's conventions—verbose but descriptive. Once you use them a few times, the patterns stick.
The cn
Dependency
This component needs the cn
utility function from shadcn/ui for class merging. If you're already using shadcn/ui, you're set. If not, you can either grab their cn
implementation or use something like clsx
with tailwind-merge
.
The cn
function handles the tricky business of merging Tailwind classes properly—something that's surprisingly complex when you need to override conflicting utilities.
What's Next
This component fills a gap I kept running into. Tailwind UI has these container patterns, shadcn/ui has the component philosophy, but nobody had bridged them into a reusable component.
If you end up using this, I'd love to hear how it works in your projects. The beauty of this approach is that it's yours to modify—no package dependencies, no version conflicts, just code you control.