<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[uselayouts]]></title><description><![CDATA[uselayouts]]></description><link>https://uselayouts.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1593680282896/kNC7E8IR4.png</url><title>uselayouts</title><link>https://uselayouts.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sun, 11 Oct 2026 16:20:02 GMT</lastBuildDate><atom:link href="https://uselayouts.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Own the Code: MIT, Sponsors, and Never Fighting Your UI Library Again]]></title><description><![CDATA[I want to tell you about the worst forty minutes I've spent on a button.
It was a button from a UI kit. A nice one. Popular, well documented, all of that. And I needed it to do one small thing it didn]]></description><link>https://uselayouts.hashnode.dev/own-the-code-mit-sponsors-and-never-fighting-your-ui-library-again</link><guid isPermaLink="true">https://uselayouts.hashnode.dev/own-the-code-mit-sponsors-and-never-fighting-your-ui-library-again</guid><category><![CDATA[React]]></category><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[open source]]></category><category><![CDATA[UI]]></category><category><![CDATA[framer-motion]]></category><dc:creator><![CDATA[Urvish]]></dc:creator><pubDate>Thu, 08 Oct 2026 04:49:53 GMT</pubDate><content:encoded><![CDATA[<p>I want to tell you about the worst forty minutes I've spent on a button.</p>
<p>It was a button from a UI kit. A nice one. Popular, well documented, all of that. And I needed it to do one small thing it didn't do: animate its width when the label changed. That's it. "Save" becomes "Saving" becomes "Saved," and the button should grow and shrink smoothly instead of jumping.</p>
<p>The kit didn't support that. So I tried a prop. There wasn't one. I tried wrapping it. The inner element had its own styles that fought my wrapper. I tried overriding the styles. I ended up with a selector so specific it looked like a riddle, plus an <code>!important</code>. It half worked. The padding was off. I fixed the padding. The focus ring broke. I fixed the focus ring. Then I updated the kit a few weeks later and all of it broke again.</p>
<p>Forty minutes on that first attempt. More later. On a button.</p>
<p>That's what I mean by fighting the library. And it's one of the big reasons useLayouts works the way it does. You don't install it. You own it.</p>
<p>This post is about ownership. What it means that useLayouts is MIT licensed and lands in your project as source code. What you can do with it. What it costs you, because it does cost something. Why I picked this model over a paid tier or a locked package. And how sponsors fit into keeping a free project alive.</p>
<p>If you're new: I'm Urvish. I build useLayouts, a free library of animated React components. You add components through the Shadcn CLI, the source lands in your project, and from then on it's your code. React, Tailwind, Motion. It was selected for the Vercel Open Source Program Winter 2026 cohort. And it's MIT, which is what most of this post is about.</p>
<h2>What "fighting the library" actually looks like</h2>
<p>Before I get into ownership, I want to describe the problem properly, because I think a lot of developers have just accepted it as normal.</p>
<p>Fighting the library is when the tool that was supposed to save you time starts costing you time, because it won't let you do what you need.</p>
<p>It shows up in a few classic ways.</p>
<h3>The missing prop</h3>
<p>You need a behavior. The component doesn't expose a prop for it. So you either live without it, or you start hacking. Every component library has to decide which things to make configurable, and they can't make everything configurable, so eventually you hit the edge.</p>
<p>For motion this is especially bad, because feel is personal. A library might expose <code>duration</code>, but you want a spring. Or it exposes a spring, but you want different springs for opening and closing. Or it animates opacity, and you need it to animate layout. Motion has so many dimensions that no prop API can cover them all.</p>
<h3>The override war</h3>
<p>You try to change how something looks, and the library's styles fight you. Specificity battles. <code>!important</code>. Wrapper divs. Global CSS that leaks into other places. You win the war, but your code now has scars that nobody understands six months later.</p>
<h3>The theme provider maze</h3>
<p>Some libraries ask you to wrap your app in a provider and configure a theme object. Changing anything means learning the library's theming system, which is its own little language. Want one component to be slightly different? Now you need to learn how to override theme values per component, per variant, per state.</p>
<h3>The upgrade landmine</h3>
<p>You finally get everything how you want it. Then you upgrade the library. An internal class name changed, or a DOM structure changed, and your overrides silently break. You don't notice until a user tells you the button looks weird.</p>
<h3>The fork</h3>
<p>The nuclear option. You fork the library or patch it in place. Now you maintain a fork of something you didn't write, and you're scared to touch it.</p>
<p>I've done every single one of these. Probably you have too.</p>
<h2>The copy model: ownership as the default</h2>
<p>useLayouts flips it. There's no package to fight because there's no package.</p>
<p>You add the registry once in your <code>components.json</code>:</p>
<pre><code class="language-json">{
  "registries": {
    "@uselayouts": "https://uselayouts.com/r/{name}.json"
  }
}
</code></pre>
<p>Then add a component by name:</p>
<pre><code class="language-bash">npx shadcn@latest add @uselayouts/discrete-tabs
</code></pre>
<p>Works the same way with other package managers:</p>
<pre><code class="language-bash">pnpm dlx shadcn@latest add @uselayouts/discrete-tabs
yarn dlx shadcn@latest add @uselayouts/discrete-tabs
bunx --bun shadcn@latest add @uselayouts/discrete-tabs
</code></pre>
<p>And you can add more than one at once:</p>
<pre><code class="language-bash">npx shadcn@latest add @uselayouts/delete-button @uselayouts/save-button
</code></pre>
<p>The source lands in your project. It's a <code>.tsx</code> file in your components folder. React and Tailwind are the only things you need ahead of time. Motion and anything else a component needs get installed for you.</p>
<p>And then it's just your code. Let's go back through those fights.</p>
<p><strong>The missing prop?</strong> Add it. It's your file. Or don't add a prop at all, just change the behavior directly.</p>
<p><strong>The override war?</strong> There's nothing to override. The Tailwind classes are right on the elements. Change them.</p>
<p><strong>The theme provider maze?</strong> There isn't one. Components use your Tailwind setup and tokens.</p>
<p><strong>The upgrade landmine?</strong> There's no upgrade that can break you. Your copy doesn't change unless you change it.</p>
<p><strong>The fork?</strong> It's already effectively a fork. That's the default state. You're not scared to touch it because it was always meant to be touched.</p>
<p>That button I fought for forty minutes? With the copy model, it's a few minutes of reading the file, finding the element, and adding Motion's layout animation. Which is, by the way, roughly what the useLayouts Save Button already does out of the box.</p>
<h2>What MIT actually means, in plain words</h2>
<p>I've had a lot of people ask me what the license means for them, so let me try to explain it like a normal person. Quick disclaimer first: I'm a developer, not a lawyer. This is my understanding as the person who picked the license. If you're making a big legal decision, read the actual license text yourself or ask someone qualified.</p>
<p>MIT is one of the most permissive open source licenses out there. The short version is:</p>
<ul>
<li>You can use it for free, including in commercial products</li>
<li>You can change it however you want</li>
<li>You can ship it in apps you sell</li>
<li>You can share your changed versions</li>
</ul>
<p>The main thing MIT asks is that the copyright and license notice stays with copies or substantial portions of the code. That's about it. There's no requirement to open source your own app. There's no requirement to pay anything. There's no "free for personal use only" clause.</p>
<p>The license is in the repo at <a href="https://github.com/iurvish/uselayouts">https://github.com/iurvish/uselayouts</a> if you want to read it yourself. It's short. Like, genuinely short. Most people are surprised by how short it is.</p>
<h3>Why I picked MIT</h3>
<p>I considered a few other options before landing on MIT, and I want to explain why.</p>
<p><strong>Copyleft licenses like GPL.</strong> These require people who distribute modified versions to share their source under the same license. That's a great fit for some projects. But for UI components that you paste into your app and change, it would create a lot of confusion. Does using a GPL tab component mean your whole app needs to be GPL? People would hesitate, or avoid it entirely, and honestly, I'd rather they just use it.</p>
<p><strong>A source available license with commercial restrictions.</strong> Some projects do "free for individuals, paid for companies." I get why. But it means every developer at a company has to ask legal before trying a component. That kills the "try it tonight" thing completely. I want someone to be able to add Discrete Tabs at 1am without emailing anybody.</p>
<p><strong>Free plus a paid "pro" tier.</strong> A lot of UI libraries do this. The basic stuff is free, and the really good stuff is paid. I thought about it seriously, because money is nice. But it felt wrong for what I was trying to do. If the best interactions are paywalled, the free version is basically an ad. And then I'd have this incentive to keep the good stuff out of the free version. I didn't want that incentive living in my brain.</p>
<p><strong>MIT won</strong> because it matches the whole idea of useLayouts. You own the code. Not "you can look at the code." Not "you own it if you pay." You own it. The license should say the same thing the product says.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ac68ba6462e32c088eb592c/32fd6755-d300-497d-983b-642c447519e2.png" alt="useLayouts home hero" style="display:block;margin:0 auto" />

<h2>You can see exactly what you're getting before you get it</h2>
<p>Here's a part of ownership people don't talk about much: transparency before you install.</p>
<p>With a lot of packages, you install first and find out later what came with it. Transitive dependencies, side effects, global styles, whatever. You trust the package name and hope.</p>
<p>With the registry, every component is a JSON file at a public URL. The pattern is the same one you put in your <code>components.json</code>: <code>https://uselayouts.com/r/{name}.json</code>. So for Discrete Tabs, it's <code>https://uselayouts.com/r/discrete-tabs.json</code>.</p>
<p>You can open that in your browser before you run anything. It tells you the component's name, its description, which dependencies the CLI will install, and the actual files it'll put in your project, including the source.</p>
<p>I really like this. It means you can make an informed decision. If you look at a component and see it needs a dependency you don't want in your app, you know before you add it. If you want to read the source first to see whether it fits your codebase, you can.</p>
<h3>What the dependency lists tell you</h3>
<p>When I look across the registry, a pattern shows up that I'm kind of proud of. A lot of components only need <code>motion</code>, <code>clsx</code>, and <code>tailwind-merge</code>. Discrete Tabs is like that. A few need nothing beyond that, or even less. Some pull in an icon package. And then the bigger ones, like the Multi Step Form, pull in more, because they're doing more: form state, validation, toasts.</p>
<p>I try to keep dependencies honest. If a component can do its job with Motion and Tailwind, it doesn't get anything extra. If it genuinely needs something, like a drawer primitive or validation, it uses a proven library instead of me reinventing one badly. Either way, you can see the list up front.</p>
<h3>Why this matters for ownership</h3>
<p>Ownership isn't just "the file is in your repo." It's knowing what you own. If code shows up in your project and you have no idea what it depends on or why, you don't really own it. You're just storing it.</p>
<p>Being able to see the registry entry, see the dependencies, read the source, and then decide to add it, that's real ownership. You're choosing to take on this code with your eyes open.</p>
<p>It also makes code review way easier on teams. Someone wants to add a component? Link the registry JSON in the PR. Everyone can see what's coming in. Then the PR itself shows the actual files landing in the repo. No mystery.</p>
<h3>A small habit I'd recommend</h3>
<p>Before adding a component to a serious project, spend two minutes with its registry entry or its docs page. Each component page on the site has a live preview, the install command, and the source you'll get. Play with the preview. Skim the source. Check the dependencies. Then add it.</p>
<p>Two minutes up front saves you from the "wait, why is this here?" moment three months later.</p>
<h2>Ownership isn't free: the real costs</h2>
<p>I'd be lying if I said owning the code had no downsides. It does. I think they're worth it, but you should know what you're signing up for.</p>
<h3>Cost one: updates don't come to you</h3>
<p>When I improve a component, your copy doesn't change. If I fix a subtle bug in how Discrete Tabs handles fast clicks, you won't get that fix automatically. You'd have to re-add the component, or look at what changed and bring it over yourself.</p>
<p>This is the flip side of "no upgrade can break you." No upgrade can break you, and no upgrade can help you either, unless you go get it.</p>
<p>How I'd handle it: for the handful of components that really matter in your app, check back on the repo every now and then. Look at the commits for those files. If something looks useful, pull it in. For the components you've heavily customized, you probably don't want my changes anyway.</p>
<h3>Cost two: you're the maintainer now</h3>
<p>Once the file is in your project, it's yours to maintain. If a new React version changes something, you deal with it. If your Tailwind setup changes, you update the classes.</p>
<p>In practice, these components are pretty small and use stable stuff. React, Tailwind, Motion. They don't do anything wild. But "small and stable" isn't "zero maintenance," and I'm not going to pretend it is.</p>
<h3>Cost three: drift</h3>
<p>If you add ten components and customize each one a little differently, your app can end up inconsistent. One component springs one way, another eases a different way. With a locked library, everything at least feels the same, even if it's the same in a boring way.</p>
<p>The fix is a feel pass. After you add a few components, open them all and nudge their transitions toward one personality for your product. Match radius and colors. It takes like twenty minutes, and it's way easier than fighting a library into feeling like yours.</p>
<h3>Cost four: you have to read the code</h3>
<p>With a package, you can stay at the surface. Import, pass props, done. With owned code, at some point you're going to open the file and read it. For some people that's a feature. For others it's homework.</p>
<p>I try really hard to make the files easy to read. No internal framework, no shared base classes, no clever abstractions. React state, JSX with Tailwind classes, Motion transitions. If you can read a normal React component, you can read a useLayouts one.</p>
<h2>Living with owned components: a few habits</h2>
<p>Since ownership comes with some responsibility, here are habits I'd recommend. I use them myself in my own projects.</p>
<p><strong>Leave a comment at the top saying where it came from.</strong> Something like "Based on useLayouts Discrete Tabs" with the link. Future you will thank you. It also makes it easy to check the repo later for updates. And it's a nice way to keep the MIT notice spirit alive.</p>
<p><strong>Customize in the file, not around it.</strong> Don't wrap an owned component in another component just to change its styles. That's the override war again, but with yourself. Just change the file.</p>
<p><strong>Rename freely.</strong> If your codebase calls things <code>items</code> and the component calls them <code>tabs</code>, rename them. If your folder structure wants a different file name, rename the file. Owned code should look like the rest of your codebase.</p>
<p><strong>Delete what you don't use.</strong> If you don't need icons in the tabs, delete that code. If you don't need a certain state, delete it. Smaller files are easier to own.</p>
<p><strong>Keep a note of what you changed.</strong> Not a big doc. Just a comment like "Tightened spring for dashboard use, removed hover state." When you look at the original later to pull in an update, you'll know which differences are yours on purpose.</p>
<h2>Walkthrough: owning the Pricing Card</h2>
<p>Let me make this concrete. I'll walk through what owning a component looks like with the Pricing Card.</p>
<pre><code class="language-bash">npx shadcn@latest add @uselayouts/pricing-card
</code></pre>
<p>When you run that, the CLI drops the component into your project and installs what it needs. For this one, that includes Motion, plus NumberFlow for animating numbers, plus a couple of icon packages and the usual <code>clsx</code> and <code>tailwind-merge</code>. You don't have to set any of that up yourself.</p>
<p>Now it's yours. Here's what owning it looks like for a real product.</p>
<p><strong>Your plans aren't my plans.</strong> The default content is placeholder. Replace it with your actual tiers, your actual features, your actual prices. This is the obvious part.</p>
<p><strong>Your hierarchy might be different.</strong> The Pricing Card is built around a focused layout with clear hierarchy. But maybe your product has one plan that matters way more than the others, or you want a different thing emphasized. Move stuff around. Change what's big and what's small.</p>
<p><strong>Your numbers might move differently.</strong> If your pricing switches between monthly and yearly, the number animation is a nice touch, because it shows the price changing instead of just swapping text. That's feedback. But if your product is super minimal, maybe you want that motion quicker and quieter. Tune it.</p>
<p><strong>Your brand has opinions.</strong> Colors, fonts, radius, shadows. All Tailwind classes, all right there.</p>
<p>If this were a locked package, every one of those changes would be a question of "does the library let me?" With an owned file, every change is just an edit.</p>
<h2>Walkthrough: owning the Multi Step Form</h2>
<p>The Multi Step Form is a good example of a bigger component, and how ownership plays out when there's more going on.</p>
<pre><code class="language-bash">npx shadcn@latest add @uselayouts/multi-step-form
</code></pre>
<p>This one pulls in more dependencies because it does more. Motion for the step transitions, react-hook-form and zod for validation, sonner for toasts, date-fns, lucide-react for icons, react-use-measure, and the usual helpers. The CLI handles all of it.</p>
<p>Now, here's where ownership really matters. Forms are almost never generic. Your onboarding asks for your fields. Your validation rules are your rules. Your steps are your steps.</p>
<p>With a locked form library, you'd be configuring all of that through some schema format the library invented, and the moment you need something it didn't anticipate, you're fighting it again.</p>
<p>With the owned file, you see exactly how it's put together. The steps. The validation schema in zod. The transitions between steps. You change the fields to what you need. You rewrite the schema for your rules. You keep the transitions, because making each step flow into the next is the part that makes a form feel like progress instead of paperwork.</p>
<p>And if you already use a different validation library in the rest of your app? You can swap it. That's a bigger edit, sure. But it's possible, and it's your call. Nobody's stopping you.</p>
<h2>Walkthrough: gutting Discrete Tabs on purpose</h2>
<p>The docs say something I really mean: don't treat these as finished products, treat them as a starting point you can ruin on purpose.</p>
<p>So let me show you what ruining it on purpose looks like.</p>
<pre><code class="language-bash">npx shadcn@latest add @uselayouts/discrete-tabs
</code></pre>
<p>Discrete Tabs is pretty lean already. Its dependencies are just Motion, <code>clsx</code>, and <code>tailwind-merge</code>. It's a tab component with a sliding indicator that follows your choice.</p>
<p>Say you're putting it into a dense dashboard. Here's what I might do:</p>
<ul>
<li>Strip the padding way down so the tabs are compact</li>
<li>Change the indicator from a background pill to a thin underline, by changing a few classes</li>
<li>Make the spring much stiffer, so it feels instant but still slides</li>
<li>Remove anything decorative that doesn't help in a dashboard context</li>
<li>Rename the component to match my app's naming, like <code>ViewSwitcher</code></li>
</ul>
<p>After that, honestly, it might not look much like the original at all. The core idea, an indicator that slides between choices and tells you where you are, is still there. Everything else is mine.</p>
<p>That's not misusing the component. That's the intended use. The best compliment someone can give a useLayouts component is "I changed it so much I barely recognize it, but it still feels great."</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ac68ba6462e32c088eb592c/86bbee46-22b6-497d-abee-674d1cb1b8e2.png" alt="Browsing the useLayouts component wall" style="display:block;margin:0 auto" />

<h2>Ownership on a team</h2>
<p>Most of what I've said so far applies to solo builders, but ownership matters on teams too, maybe even more.</p>
<p>There's a line in the docs about this: drop a component in, make it match your design system, and stop debating hover opacity in Slack.</p>
<p>I wrote that half as a joke, but it's real. Teams can burn a surprising amount of time debating tiny interaction details. Should this fade or slide? How long should the hover take? Should the indicator overshoot a little? Everyone has an opinion, nobody has a reference, and the conversation goes in circles.</p>
<p>Owned components help in two ways.</p>
<p><strong>They give you a starting reference.</strong> Instead of debating from nothing, you start from something that already feels considered. The conversation goes from "how should tabs work?" to "this feels a bit slow for us, can we make it snappier?" That's a much shorter conversation.</p>
<p><strong>They live in your design system, not next to it.</strong> Because the files are in your repo, they can follow your conventions. Your token names. Your folder structure. Your lint rules. Your review process. A team member reviewing a PR can see exactly what changed in a component, because it's just code in the diff. Nobody has to dig through a package's changelog to figure out why something looks different.</p>
<h3>What I'd suggest for teams</h3>
<p>If you're on a team and want to use useLayouts, here's how I'd approach it:</p>
<ol>
<li><strong>Pick one owner for the animated components.</strong> Doesn't need to be a full time role. Just one person who does the feel pass and keeps things consistent.</li>
<li><strong>Add components to your shared component folder</strong>, not scattered around feature folders. Treat them like part of your design system from day one.</li>
<li><strong>Customize once, centrally.</strong> Tune the springs and tokens in one place, so every feature using the component gets the same feel.</li>
<li><strong>Document your changes lightly.</strong> A comment at the top of each file saying where it came from and what you changed.</li>
<li><strong>Review updates on purpose.</strong> Every so often, look at the useLayouts repo for components you use. Pull in what's helpful. Ignore what isn't.</li>
</ol>
<p>None of this is complicated. It's just treating the components like code you own, because you do.</p>
<h2>The maintainer side: what ownership means for me</h2>
<p>Ownership changes things for me too, as the person building useLayouts. It's not just a user facing idea.</p>
<h3>I can't push fixes into your app</h3>
<p>With a normal package, if I find a bug, I publish a patch and everyone who updates gets it. With useLayouts, I can't do that. Once you have the code, my fix only reaches you if you go get it.</p>
<p>That makes me more careful before shipping. I test components harder than I probably would if I could just patch them later. Fast clicks. Keyboard only. Phone. Dark mode. Weird parent layouts. Because the version you add might be the version you keep for a long time.</p>
<h3>Readability is a feature I have to build</h3>
<p>Since the code is the product, I can't hide complexity behind an API. If a component is confusing to read, that's a bug, even if it works perfectly.</p>
<p>So I spend real time on readability. Clear state names. Predictable class ordering. No clever tricks. Comments where something non obvious is happening. Sometimes I rewrite a component that works fine just because it's hard to follow.</p>
<h3>Registry stability matters</h3>
<p>The install command is a kind of promise. When someone runs <code>npx shadcn@latest add @uselayouts/discrete-tabs</code>, they're trusting that name to keep working. If I rename or remove things carelessly, I break people's workflows and their docs and their tutorials.</p>
<p>So I think hard before renaming anything. Being in the Vercel Open Source Program Winter 2026 cohort made me even more aware of this, because more people started depending on the registry being there and being stable.</p>
<h3>I let go of control</h3>
<p>This is the emotional part. When you build something with a lot of care, it's tempting to want it used exactly how you made it. With the copy model, I have to let that go. People will change my springs. They'll remove the details I spent a night on. They'll make the indicator do something I'd never do.</p>
<p>And that's the point. If I wanted control, I'd have shipped a locked package. Giving people ownership means trusting them with it. Honestly, it's freeing. My job is to give you a really good starting point. What you do with it is up to you.</p>
<h2>Sponsors: how a free project stays alive</h2>
<p>Okay, money. Let's talk about it honestly, because I think open source people are often weird about it.</p>
<p>useLayouts is free. It's MIT. There's no paid tier. I'm not planning to add one. But running a project like this does take time and resources. Building components, testing them, writing docs, keeping the site and registry running, answering issues. Someone has to do it, and right now that someone is me.</p>
<h3>How I think about sponsorship</h3>
<p>My approach is simple, and it's the same thing the docs say:</p>
<p><strong>If you're building something small and personal, take what you need and ship.</strong> You don't owe me anything. Seriously. The whole point is to give people a better starting point than another dead hover.</p>
<p><strong>If a company gets value from it, sponsor so the lights stay on.</strong> If your company ships a product using useLayouts components, and those components are saving your team time or making your product feel better, sponsoring is how you help keep it going for everyone else. There's a sponsor page on the site.</p>
<p>I really like this setup because it puts the cost where the value is. A student building a portfolio doesn't pay. A company making money with it can choose to give some back. Nobody's forced. Nobody's locked out.</p>
<h3>Why not just paywall stuff?</h3>
<p>I touched on this earlier with the license, but I want to say it again from the money angle.</p>
<p>Paywalling would probably make more money in the short term. I'm not naive about that. But it would change what useLayouts is. The incentive would shift from "make the free components as good as possible" to "keep the best stuff behind the paywall." I'd be thinking about every new component as "free or paid?" instead of "is this good?"</p>
<p>I don't want to think like that. I want every component to be as good as I can make it, and I want everyone to have it.</p>
<h3>What sponsorship actually pays for</h3>
<p>I'm not going to share numbers, because I don't want to invent anything or set weird expectations. But in general, support for a project like this goes toward the stuff that keeps it healthy:</p>
<ul>
<li>Time to build and polish new components carefully, instead of rushing</li>
<li>Time to go back and improve old components</li>
<li>Time to answer issues and help people with their setups</li>
<li>Keeping the docs, live previews, and registry running well</li>
</ul>
<h3>Where Vercel OSS fits</h3>
<p>The Vercel Open Source Program helps with part of this. useLayouts was selected for the Winter 2026 cohort, which comes with credits and support from Vercel. That helps a lot with the infrastructure side, like running the docs site and the registry.</p>
<p>But I want to be clear that a program like that is one piece, not the whole picture. It doesn't replace sponsors and it isn't a salary. It's support at a moment in time that helps a project grow. Long term, open source projects stay alive because of a mix of things: programs, sponsors, contributors, and people who just care and tell their friends.</p>
<h3>Non money ways to help</h3>
<p>If you can't or don't want to sponsor, there are still ways to help that genuinely matter:</p>
<ul>
<li><strong>Star the repo on GitHub.</strong> It helps other developers find it. We're at hundreds of stars and climbing, and every one helps.</li>
<li><strong>Tell someone.</strong> If useLayouts saved you a night, tell a friend or post about it.</li>
<li><strong>Report bugs well.</strong> A clear bug report with a small reproduction is incredibly valuable.</li>
<li><strong>Share how you customized something.</strong> Seeing how people change components teaches me a ton about what to improve.</li>
</ul>
<h2>Contributing to an owned code library</h2>
<p>People sometimes ask how contributing works when everyone has their own copy. Good question.</p>
<p>The repo at <a href="https://github.com/iurvish/uselayouts">https://github.com/iurvish/uselayouts</a> is the source for the registry. When something gets improved there, it's improved for everyone who adds that component from then on. So contributions still matter a lot.</p>
<p>The most helpful contributions, in my experience:</p>
<p><strong>Bug reports with context.</strong> "Discrete Tabs indicator jumps when tabs wrap to two lines on mobile" is way more useful than "tabs broken." If you can include your setup or a small example, even better.</p>
<p><strong>Feel feedback.</strong> This is unusual for a code project, but for useLayouts it's really valuable. "The Smooth Dropdown feels too slow on a phone" or "the Delete Button confirm state resets too fast" is exactly the kind of feedback that makes components better.</p>
<p><strong>Accessibility findings.</strong> If you notice a component doesn't work well with a keyboard or a screen reader, please tell me. That's top priority stuff.</p>
<p><strong>Ideas for interactions.</strong> Not "add 50 more buttons," but "this specific moment in my app feels rude and I wish there was a component for it." That's the kind of thing useLayouts is built for.</p>
<h2>Why feel can't be a prop</h2>
<p>I want to go a bit deeper on why ownership matters especially for motion, because I think it's the strongest argument for the whole model.</p>
<p>Think about what goes into how an interaction feels. The spring stiffness. The damping. The mass. Whether there's overshoot. How long the exit takes compared to the enter. Whether the indicator moves before or after the content changes. Whether the hover reacts right away or waits a beat. Whether pressing scales down a little, or not at all. Whether things move along a path or just fade.</p>
<p>Now imagine trying to expose all of that as props. You'd have a component with forty animation props, and it still wouldn't cover the case where you want the indicator to stretch a little while moving, or the content to slide from the direction of the tab you came from.</p>
<p>Motion is too expressive for a prop API to hold. Any locked component has to pick a small subset of what's possible, and that subset becomes your ceiling.</p>
<p>When you own the file, there's no ceiling. You have the full Motion API right there. If you want the indicator to stretch, you add that. If you want direction aware content, you add that. You're not configuring an animation. You're writing one, starting from a good draft.</p>
<p>That's the core reason useLayouts is copy, customize, ship and not a package. It's not a philosophical stance about open source purity. It's that motion is personal, and personal things shouldn't be locked.</p>
<p>It also connects to the docs philosophy. Every animation should do a job: feedback, focus, or flow. If it only looks expensive, cut it. You can only cut what you own. With a package, you'd be stuck with whatever decoration it shipped. With an owned file, if the hover on a Bento Card doesn't do a job in your product, you delete it. Done.</p>
<h2>A tale of two nights</h2>
<p>Let me compare two nights, because I think the difference between fighting and owning is easiest to feel in a story.</p>
<h3>Night one: the locked kit</h3>
<p>It's late. I'm building a settings page for a project. I need vertical tabs on the left, content on the right. The kit I'm using has a tabs component, but it's horizontal by default. There's an orientation prop. Great. I set it to vertical.</p>
<p>It works, but the indicator still animates like it's horizontal, sliding sideways for a split second before snapping into place. Looks broken. I search the docs. Nothing. I search the issues. Someone else had the same problem a while back. The issue is still open.</p>
<p>I try to override the indicator's transition. The indicator is an internal element with a generated class name. I target it with a selector that depends on the DOM structure. It works. I feel dirty.</p>
<p>Then I want the content panel to fade between tabs. The kit swaps content instantly. There's no transition prop for content. I try wrapping the content in my own animation wrapper. The kit unmounts the old panel before my wrapper can animate it out. So I get a fade in but no fade out. It feels lopsided.</p>
<p>At this point it's past 1am. I've written a bunch of code that exists purely to fight the library, and the result still feels kind of off. I ship it. I'm annoyed.</p>
<h3>Night two: the owned file</h3>
<p>Same project idea, different approach. I need vertical tabs for settings.</p>
<pre><code class="language-bash">npx shadcn@latest add @uselayouts/vertical-tabs
</code></pre>
<p>The file lands in my project. I open it. It's built for vertical from the start, so the indicator moves in the right direction. Content switches smoothly.</p>
<p>But say I want something slightly different. Maybe I want the content to slide a little instead of just switching. I find where the content transition is defined. It's right there, a few lines of Motion. I change it. Done.</p>
<p>Maybe I want the indicator to be a thin bar instead of a filled background. I find the indicator element, change its Tailwind classes. Done.</p>
<p>Maybe my settings sections have icons and the component's icons don't match my app. I swap the icon imports. Done.</p>
<p>I'm finished well before midnight, and none of the code I wrote is fighting anything. It's all just product code. If someone on my team opens this file later, they'll understand it, because it's plain React with Tailwind and Motion.</p>
<p>That's the difference. Night one, the library was the obstacle. Night two, the library was a head start.</p>
<h2>When owning the code is the wrong choice</h2>
<p>I'd be a bad advocate for ownership if I said it was always right. It isn't.</p>
<p><strong>If you never want to think about UI code, a locked package might suit you better.</strong> Some teams want to install something, use it as is, and never open it. That's a valid choice. Owned code asks a bit more of you.</p>
<p><strong>If you need guaranteed updates across a huge codebase, owned code is more work.</strong> If you have dozens of teams using the same components and you need a security or accessibility fix to reach all of them at once, a package with versioning might be easier to coordinate. With owned components, you'd need your own internal process for that.</p>
<p><strong>If the component is truly generic plumbing, ownership might not buy you much.</strong> For something like a basic primitive with complex accessibility behavior, using a well maintained primitive library makes more sense than owning every line. That's why useLayouts focuses on interaction details, the moments where feel matters, and not on replacing the primitives you already use.</p>
<p>My honest take: for motion and interaction polish, owning is almost always better. For basic plumbing, it depends. Use the right tool for each layer.</p>
<h2>What I hope people do with useLayouts</h2>
<p>When I picture the best version of how people use this, it's not "everyone's app has the same Discrete Tabs." It's more like:</p>
<p>Someone adds a component. They open the file. They learn something about how the interaction works, maybe how a layout animation handles different tab widths, or how a confirmation state resets. Then they change it into something that fits their product. And next time they need a similar interaction, they're a bit more confident building it themselves.</p>
<p>Ownership isn't just about legal rights. It's about understanding. When the code is yours, you learn from it. A locked package teaches you its API. An owned file teaches you how the thing actually works.</p>
<p>That's my favorite side effect of the whole model. useLayouts isn't just a shortcut. It can be a way to get better at building interfaces that feel alive.</p>
<h2>FAQ</h2>
<p><strong>Can I use useLayouts in a commercial product?</strong></p>
<p>Yes. It's MIT licensed, which allows commercial use. Keep the copyright and license notice with the code as MIT asks. And again, I'm not a lawyer, so read the license in the repo if you need certainty.</p>
<p><strong>Do I have to credit useLayouts in my app's UI?</strong></p>
<p>No, MIT doesn't require visible credit in your product's interface. The license notice should stay with the code. That said, if you want to give a shout out somewhere, I'd love that.</p>
<p><strong>Can I modify the components?</strong></p>
<p>Please do. That's the whole point. Change the spring, swap the copy, delete half of it.</p>
<p><strong>Do I have to open source my app if I use useLayouts?</strong></p>
<p>No. MIT doesn't require that.</p>
<p><strong>Will there ever be a paid version?</strong></p>
<p>No plans for one. It's free, MIT, and sponsors are welcome from companies who get value from it.</p>
<p><strong>How do I get updates?</strong></p>
<p>Watch the repo for the components you use. If something improves, re-add the component or bring over the changes you want. Your copy never changes on its own.</p>
<p><strong>What do I need installed?</strong></p>
<p>React and Tailwind. Set up the registry in your <code>components.json</code>, then use the Shadcn CLI. Motion and other dependencies a component needs get installed for you.</p>
<p><strong>Can my company sponsor?</strong></p>
<p>Yes, and thank you if you do. There's a sponsor page on the site. If your team ships useLayouts components in a product, sponsoring is the best way to help keep the project free and maintained.</p>
<p><strong>Is useLayouts the same as UI Layouts?</strong></p>
<p>No. Different projects, different creators. ui-layouts.com is a separate library. Both happen to be in the Vercel OSS program, which makes the name mix-up even easier. useLayouts is the one with the <code>@uselayouts</code> registry and the repo at github.com/iurvish/uselayouts.</p>
<p><strong>Can I look at a component before installing it?</strong></p>
<p>Yes. Every component has a docs page with a live preview, the install command, and the source. You can also open its registry JSON directly, like <code>https://uselayouts.com/r/discrete-tabs.json</code>, to see the dependencies and files the CLI will add.</p>
<p><strong>Can I put useLayouts components in a template or starter I share?</strong></p>
<p>MIT allows redistribution, as long as the copyright and license notice comes along with the code. If you're doing that, I'd appreciate a link back so people can find the originals and the docs. And if you're turning it into a paid product, maybe consider sponsoring. Not required. Just nice.</p>
<p><strong>What if I find something broken?</strong></p>
<p>You can fix it in your copy right away, since it's yours. And then please open an issue so I can fix it for everyone else too.</p>
<h2>Wrapping up</h2>
<p>The worst forty minutes I spent on a button weren't really about the button. They were about not being allowed to change something I was supposedly using. That's what fighting the library feels like. You're the developer, it's your product, and some package is telling you no.</p>
<p>useLayouts is my answer to that. MIT licensed, free, and delivered as source code that lands in your project. You own it. You change it. You never have to fight it, because there's nothing to fight.</p>
<p>Ownership has costs. Updates don't come to you automatically. You maintain what you keep. You have to read a bit of code. I think those costs are worth it, especially for motion, where feel is personal and can't be squeezed into a prop list.</p>
<p>And the project stays alive the open source way. People who need a better starting point take what they need. Companies who get value sponsor. Programs like the Vercel Open Source Program help with infrastructure. And everyone who stars the repo or tells a friend helps other developers find it.</p>
<p>If you want to see what owning a component feels like, add one tonight and open the file.</p>
<pre><code class="language-bash">npx shadcn@latest add @uselayouts/discrete-tabs
</code></pre>
<p>Break it on purpose. Make it yours. And if it saves you a fight with a library, a star on GitHub would make my day.</p>
<p>Urvish</p>
<hr />
<ul>
<li>Site: <a href="https://uselayouts.com/">https://uselayouts.com/</a></li>
<li>Docs: <a href="https://uselayouts.com/docs/introduction">https://uselayouts.com/docs/introduction</a></li>
<li>GitHub: <a href="https://github.com/iurvish/uselayouts">https://github.com/iurvish/uselayouts</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Motion That Means Something: Feedback, Focus, and Flow]]></title><description><![CDATA[There's one line in the useLayouts docs that I think about more than any line of code I've written.
"Every animation here is supposed to do a job: feedback, focus, or flow. If it only looks expensive,]]></description><link>https://uselayouts.hashnode.dev/motion-that-means-something-feedback-focus-and-flow</link><guid isPermaLink="true">https://uselayouts.hashnode.dev/motion-that-means-something-feedback-focus-and-flow</guid><category><![CDATA[Open Source]]></category><category><![CDATA[UI]]></category><category><![CDATA[React]]></category><category><![CDATA[Next.js]]></category><dc:creator><![CDATA[Urvish]]></dc:creator><pubDate>Wed, 07 Oct 2026 18:24:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ac68ba6462e32c088eb592c/af83ed01-c2af-48c5-ab58-2d08676201a1.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There's one line in the useLayouts docs that I think about more than any line of code I've written.</p>
<p>"Every animation here is supposed to do a job: feedback, focus, or flow. If it only looks expensive, cut it."</p>
<p>That's the whole philosophy. Everything else in the library comes out of it. Which components exist, how long they animate, what moves and what doesn't, what I deleted after a week of living with it.</p>
<p>I'm Urvish. I build useLayouts, a free MIT collection of animated React components made with Tailwind and Motion, distributed through a shadcn registry. It got picked for the Vercel Open Source Program Winter 2026 cohort, which still feels unreal. But this post isn't really about the library. It's about the thinking behind it. How I decide whether a piece of motion deserves to exist, and how you can make that call in your own projects, whether you ever use a single component of mine or not.</p>
<p>Fair warning, this is long. I've had a lot of opinions bottled up.</p>
<p><img src="https://cdn.hashnode.com/uploads/covers/6ac68ba6462e32c088eb592c/9be7eebe-4e92-4ee9-b638-86ce79d3739a.png" alt="useLayouts discrete tabs" /></p>
<h2>The problem with "make it pop"</h2>
<p>I think most bad motion on the web comes from one request: make it feel more alive.</p>
<p>That request is totally valid. Static interfaces can feel cold. But the usual response is to add motion everywhere. Fade in every section on scroll. Scale every card on hover. Bounce every button. Slide in every modal from a different direction. And the result is an interface that moves constantly but doesn't actually say anything.</p>
<p>It's like someone who talks with their hands so much you stop being able to tell which gestures matter.</p>
<p>When everything moves, nothing stands out. Your users' eyes get pulled in ten directions. The page feels busy. On slower devices, it feels janky. And the moments where motion actually could help, like telling someone their save worked, get lost in all the noise.</p>
<p>The fix isn't less motion, exactly. It's motion with a reason. And the reasons, as far as I can tell, come down to three.</p>
<h2>Feedback: "I heard you"</h2>
<p>The first job motion can do is feedback. Telling the user that something happened because of what they did.</p>
<p>This is the most important one, and I think the most underused. Every time someone clicks, taps, drags, or types, they're asking the interface a question. "Did that work?" Static UI answers that question late or not at all. Motion can answer it immediately.</p>
<p>Think about pressing a physical button. It goes down. It clicks. Maybe it lights up. You never wonder if it registered. Now think about clicking a web button that does a server request. Often nothing happens for a moment. Then maybe a spinner. Then maybe the page changes. That gap, where you don't know if it heard you, is where people double click, rage click, or give up.</p>
<p>Good feedback motion closes that gap.</p>
<p>In useLayouts, the Status Button is basically a feedback component and nothing else. You click it, and it immediately changes to show it's working. Then it changes again when it's done. Each change is animated so it feels like the same button changing its state, not three different buttons swapping places. The width animates instead of jumping. The label transitions instead of snapping. You never wonder whether it heard you. (If you go looking for it in the registry, it's the one called <code>save-button</code>.)</p>
<p>The Delete Button is feedback too, but a different kind. When you're about to destroy something, the feedback isn't just "I heard you." It's "are you sure, because this is a big deal." The motion gives that action some weight. It makes deleting feel like a decision, not a CSS class. A plain red button that instantly removes a row says "this is trivial." A delete that flips into a short countdown you can cancel says "this matters, and I'm treating it like it matters."</p>
<p>Here are a few feedback principles I've landed on:</p>
<p><strong>Feedback should start instantly.</strong> The first frame of response should happen on the input, not after the server replies. If the click starts the transition, the user knows they were heard, even if the result takes a second.</p>
<p><strong>Feedback should be proportional.</strong> Saving a form field doesn't deserve confetti. Deleting your whole account maybe deserves a pause. The size of the motion should match the size of the action. My first Status Button had a celebratory bounce on success and it felt ridiculous for saving a text field. I cut it.</p>
<p><strong>Feedback should resolve.</strong> Don't leave the UI stuck in a "success!" state forever. Show it, let it land, then go back to normal. Otherwise the feedback becomes just another piece of static UI.</p>
<p><strong>Feedback should be about the thing you touched.</strong> If you click a button, the button should respond. Not a toast in the opposite corner of the screen. Toasts are fine as a backup, but the main response should be right where your attention already is.</p>
<h2>Focus: "look here"</h2>
<p>The second job is focus. Directing attention to what matters right now.</p>
<p>Interfaces are full of things competing for attention. Motion is one of the strongest attention tools there is, because our eyes are wired to notice movement. That's exactly why it's dangerous to overuse, and exactly why it's powerful when used on purpose.</p>
<p>Focus motion says: of everything on screen, this is the thing to look at.</p>
<p>Discrete Tabs is a focus component. It's a row of pills. The inactive ones are compact, just an icon. The active one opens up to show the icon and the label. When you switch tabs, the old active pill shrinks back to its icon and the new one opens up, and everything slides to make room.</p>
<p>What that does is make it really obvious, at a glance, which tab you're on. Not because it's a different color, though it is, but because it's literally bigger and it has words. Your eye goes straight to it. And when you switch, the movement draws your eye to the new active tab, so you never lose your place.</p>
<p>A gallery that expands one image while the others recede is focus. A card that lifts slightly when you hover, while the rest of the grid stays still, is focus. A form field that subtly highlights when it's the current step is focus.</p>
<p>Focus principles:</p>
<p><strong>Only one thing gets focus at a time.</strong> If two things are animating for attention, neither wins. Pick one.</p>
<p><strong>Focus motion should be relative.</strong> It's not just about the thing that moves. It's about the contrast with things that don't. Discrete Tabs works because the inactive tabs get smaller as the active one gets bigger. The relationship is the signal.</p>
<p><strong>Let focus fade.</strong> Once someone's looking at the right thing, stop pulling. In Discrete Tabs, the label blurs into focus in about 200ms and then just sits there. Nothing keeps pulsing or glowing to remind you which tab is active. It's a nudge, not a siren.</p>
<p><strong>Don't steal focus without permission.</strong> Auto animating something the user didn't ask about pulls their attention away from what they were doing. That's rude. Motion that grabs focus should usually be in response to something the user did, or something genuinely important.</p>
<h2>Flow: "here's how we got here"</h2>
<p>The third job is flow. Connecting one state to the next so the user doesn't lose track of where they are.</p>
<p>This one's subtle. A lot of interfaces change state abruptly. You click a tab and the content is just different. You submit step one of a form and step two just appears. You expand a card and a full view replaces it. Each change is a tiny moment of disorientation. Your brain has to re-scan the screen and figure out what changed.</p>
<p>Flow motion removes that re-scan. It shows you the change happening, so your brain tracks it instead of having to rebuild the picture.</p>
<p>The classic example is shared element transitions. A thumbnail in a grid grows into a full view, instead of the grid disappearing and a full view appearing. Because you saw it grow, you know exactly where it came from and where it'll go back to.</p>
<p>In useLayouts, a lot of components lean on Motion's layout animations for exactly this. In Discrete Tabs, each pill, icon, and label has its own <code>layoutId</code>, so when the layout changes, Motion animates each element from where it was to where it's going. The pills don't teleport. They move. You see the old active tab shrink and the new one grow, and your brain understands it as one continuous change instead of two separate states.</p>
<p>The Multi-Step Form is flow too. Sliding between steps tells you that you're moving forward through something. It makes a form feel like progress instead of paperwork. Same with the Morphing Input, where an input changes shape instead of being swapped out, so you understand it's still the same thing, just doing something different now.</p>
<p>Flow principles:</p>
<p><strong>Preserve identity.</strong> If something on screen is the "same thing" before and after a change, animate it as the same thing. Don't fade it out and fade a copy in.</p>
<p><strong>Direction matters.</strong> Moving forward should feel like moving forward. If step two slides in from the right, going back should slide from the left. Inconsistent direction is worse than no motion, because it actively lies about where you are.</p>
<p><strong>Flow should be fast.</strong> The point is to help you track a change, not to make you watch it. If the transition is so slow you're waiting for it, it's become the opposite of flow.</p>
<p><strong>Don't animate what didn't change.</strong> If only the tab label changed, don't re-animate the whole page. Motion should map to the actual change.</p>
<h2>"If it only looks expensive, cut it"</h2>
<p>Okay, so every animation should do one of those three jobs. What about the ones that don't?</p>
<p>Cut them.</p>
<p>I know that's harsh. I know there's a whole genre of beautiful, purely decorative motion on the web, and some of it is genuinely art. I'm not against it in a portfolio or an experimental site. But in a product, an interface people use to get things done, decorative motion has a cost and almost no benefit.</p>
<p>The cost: it takes attention. It takes time. It takes performance. It adds code someone has to maintain. And it trains users to ignore motion, which makes your useful motion less effective.</p>
<p>The benefit: it looks expensive. That's it. It makes a screenshot or a demo video look nice.</p>
<p>I call it "looks expensive" because that's what it's optimizing for. The impression of polish, not actual polish. Real polish is when something feels right and you don't notice why. Expensive looking motion is when you notice the motion and think "ooh, fancy."</p>
<p>Here are some things I've cut from useLayouts components over time, and why.</p>
<p><strong>The nervous delete button.</strong> One of my early versions of the Delete Button shook when you hovered it, like it was anxious. It was funny. It got a laugh in a demo. But it was purely decorative. It didn't tell you anything the confirm step didn't already tell you, and it would get really annoying if you were deleting things in a list. Cut.</p>
<p><strong>Bouncy tab settling.</strong> Early Discrete Tabs had a much softer spring, with visible overshoot when the pills settled. It looked playful. But after a few clicks, the wobble felt like the UI couldn't make up its mind. The overshoot wasn't doing any job. It was just there. I stiffened the spring until it settled cleanly. The motion still has that springy, physical quality, but it lands.</p>
<p><strong>Scroll triggered fade ins on everything.</strong> This one's not a single component, but I've definitely shipped pages where every section faded up as you scrolled. It's the most common decorative motion on the web. Does it help? Barely. On a first visit, maybe it adds a tiny sense of reveal. On the second visit, or if you're scrolling fast to find something, it just slows you down. Content you're trying to read shouldn't make you wait. I don't use it as a default anymore.</p>
<p><strong>A success celebration.</strong> I mentioned this already, but the Status Button used to do a little scale bounce plus color change plus checkmark draw when something saved. Three effects for saving a form. I kept the color and the checkmark, the stuff that tells you it worked, and cut the bounce.</p>
<p><strong>Gradient shimmer on hover.</strong> I had a card that had a moving gradient on hover. It looked stunning in a video. In an actual grid of cards, moving your mouse across the grid made a flickering light show. Cut.</p>
<p>The test I use is simple. For any piece of motion, I ask: if I removed this, would the user lose information? Would they miss feedback, lose focus, or get disoriented by a state change?</p>
<p>If the answer is no, and it's only there because it looks cool, it goes.</p>
<h2>The moments where static UI is rude</h2>
<p>The docs say these components were built for the moments where a static UI feels rude. Waiting, deleting, switching, dragging. I want to go through each one, because I think naming these moments is the most useful thing you can take away from this post.</p>
<h3>Waiting</h3>
<p>The user did something and now they're waiting for the result. A save, a submit, a load, a search.</p>
<p>Static UI during waiting is rude because it gives no sign of life. The user doesn't know if their input registered, if something's happening, or if it's stuck.</p>
<p>The worst version is nothing at all. The button stays the same and the page just sits there. Slightly better is a disabled state, which tells you something's happening but not what. Then a spinner, which at least shows activity.</p>
<p>What I aim for is waiting that feels connected. The button you clicked transforms to show it's working, then transforms again to show the result. It's the same object, telling you a story about what happened. That's the Status Button idea.</p>
<h3>Deleting</h3>
<p>The user is about to permanently remove something.</p>
<p>Static UI during deleting is rude because it treats a big decision like a small one. A red button that instantly removes a thing, no pause, no confirmation, no sense of weight, makes it really easy to make mistakes. And the browser <code>confirm()</code> dialog, which is the default fix, is jarring and ugly and pulls you completely out of the interface.</p>
<p>Good deletion motion gives the action weight without being annoying. A moment of grace that happens right there in the button. In the Delete Button, you click, the button turns into a cancel option with a countdown, and you've got a few seconds to change your mind before anything is gone. A deliberate gap between intent and action, without a modal yelling at you. That's the idea.</p>
<h3>Switching</h3>
<p>The user is changing context. Switching tabs, toggling a setting, picking a different option.</p>
<p>Static UI during switching is rude because it teleports. One state disappears, another appears, and the user's brain has to figure out what changed. It's a small cost, but people switch tabs constantly, so it adds up.</p>
<p>Good switching motion shows the transition. The active indicator travels. The content slides or morphs. You see where you went. That's Discrete Tabs, Vertical Tabs, Smooth Dropdown, and a lot of the navigation stuff.</p>
<h3>Dragging</h3>
<p>The user is physically moving something with their pointer or finger.</p>
<p>Static UI during dragging is rude because it breaks the illusion of direct manipulation. If you drag something and it lags, or snaps in weird ways, or doesn't respond to your speed, it feels like you're not really in control.</p>
<p>Good drag motion makes the thing feel like it's in your hand. It follows your pointer closely. When you let go, it settles with physics that match how you threw it. "A grip that slides" was on my original list of things I wanted, and it's still one of the hardest things to get right.</p>
<h3>And a few more</h3>
<p>Those four are the big ones, but there are others. Hovering, where the UI could acknowledge you're pointing at something. Revealing, where hidden content becomes visible. Editing in place, where something switches from display to input. Each one is a moment where static UI is a little rude, and a little motion can make it feel like the interface is paying attention.</p>
<p><img src="https://cdn.hashnode.com/uploads/covers/6ac68ba6462e32c088eb592c/3c0129f9-722f-4b9e-972f-71a4c754152f.png" alt="useLayouts home hero" /></p>
<h2>Springs vs durations</h2>
<p>Let's get a bit technical. When you animate something in Motion, you're usually choosing between two kinds of transitions: springs and tweens.</p>
<p>A tween has a duration and an easing curve. "Go from A to B over 200 milliseconds with this curve." Predictable, precise, easy to reason about.</p>
<p>A spring has physics. Stiffness, damping, mass. "Move toward B like a spring would." You don't set the duration directly, it falls out of the physics.</p>
<p>In useLayouts, I tend to use springs for things that move and tweens for things that fade.</p>
<p>Here's a real example from Discrete Tabs. The layout animation, which is the pills resizing and moving, uses a spring:</p>
<pre><code class="language-tsx">transition={{
  layout: {
    type: "spring",
    damping: 20,
    stiffness: 230,
    mass: 1.2,
  },
}}
</code></pre>
<p>But the label appearing inside the active pill uses a short tween with a sharp curve:</p>
<pre><code class="language-tsx">initial={isLoaded ? { opacity: 0, filter: "blur(4px)" } : false}
animate={{ opacity: 1, filter: "blur(0px)" }}
transition={{
  duration: isLoaded ? 0.2 : 0,
  ease: [0.86, 0, 0.07, 1],
}}
</code></pre>
<p>Why the split?</p>
<p>Springs feel physical. When something moves position or size, a spring makes it feel like an object with weight. It accelerates naturally and settles naturally. And springs handle interruption beautifully. If you click a new tab while the previous animation is still running, a spring just redirects from wherever it currently is, with its current velocity. A tween would have to restart or do something awkward.</p>
<p>Tweens are better for opacity and blur, because those don't have a physical meaning. There's no "weight" to transparency. You just want the label to appear quickly and cleanly. A short tween with a curve that's slow at the start and end, fast in the middle, gets the label from invisible to readable without lingering in that mushy half visible state.</p>
<p>The blur is doing a specific job there too. When a label crossfades in, there's a moment where it's semi transparent and you can kind of see it but not read it. That moment looks messy. A tiny blur that clears as it fades in hides that messiness. Your eye reads it as "coming into focus" instead of "fading in weirdly."</p>
<p>This is the kind of decision I think about a lot. Not "should this animate" but "what kind of animation fits what this thing is."</p>
<h3>Picking spring values</h3>
<p>People ask me for the "right" spring values. There aren't any. But here's how I think about the knobs:</p>
<p><strong>Stiffness</strong> is how strongly it pulls toward the target. Higher stiffness means faster, snappier. Too high and it feels robotic. Too low and it feels sluggish.</p>
<p><strong>Damping</strong> is how much it resists oscillating. Higher damping means less bounce. Too low and it wobbles. Too high and it feels like it's moving through syrup.</p>
<p><strong>Mass</strong> is how heavy it is. More mass means it takes longer to get going and longer to stop, with more momentum. A little extra mass, like the 1.2 in Discrete Tabs, gives it a slightly weightier, more deliberate feel.</p>
<p>My process: start with something reasonable, then click it twenty times in a row. Not once, twenty times. Fast. Interrupt it. Spam it. Motion that feels great on one click can feel exhausting on the twentieth. If it still feels good when you're spamming it, you've got it.</p>
<h2>How long should things take?</h2>
<p>Durations are opinions, not laws, so take these as my opinions.</p>
<p>Things the user triggers directly, like a button press or tab switch, should feel nearly instant to start and should be done before the user's next thought. If they're waiting to see the animation finish before they can do the next thing, it's too long.</p>
<p>Things that reveal new content, like expanding a card or opening a dropdown, can be a bit longer, because the user's eyes need to travel to the new content anyway.</p>
<p>Things that happen a lot should be shorter than things that happen rarely. A tab bar you'll click a hundred times a day needs to be faster than an onboarding transition you'll see once.</p>
<p>Exits should usually be faster than entrances. When something leaves, the user is already done with it. Don't make them watch it go.</p>
<p>And the big one: whatever duration you pick, cut it a bit. Almost every time I've tuned an animation, the final version is shorter than my first instinct. When you're building it, you watch it closely, so you want to see it. Your users don't want to watch it. They want to use the product.</p>
<h2>Motion should respond, not perform</h2>
<p>There's a rule hiding inside all of this that I want to call out on its own: motion should respond to the user. If nobody did anything, nothing should move.</p>
<p>A real example. In Discrete Tabs, look at that label transition again:</p>
<pre><code class="language-tsx">initial={isLoaded ? { opacity: 0, filter: "blur(4px)" } : false}
</code></pre>
<p><code>isLoaded</code> starts as <code>false</code> and flips to <code>true</code> the first time you click a tab. Before that, <code>initial</code> is <code>false</code>, which tells Motion "don't animate in, just render in the final state." The duration is also zero until you've interacted.</p>
<p>So when the page first loads, the tabs just appear, already settled. No entrance animation. Then once you click, everything animates.</p>
<p>Why bother? Because an entrance animation on page load is the component performing for nobody. The user hasn't asked it anything. It's just showing off. And on a page with a bunch of components, all of them animating on load at once, it looks chaotic, like the page is assembling itself in front of you.</p>
<p>Once you click, the motion becomes a response. You asked, it answered. That's the relationship I want between the user and the UI.</p>
<p>This isn't an absolute rule. Sometimes a subtle entrance on load is genuinely helpful, like guiding attention to the main action on an empty state. But it should be the exception you choose on purpose, not the default you forget to turn off.</p>
<h2>Interruptibility</h2>
<p>A thing that separates motion that feels good from motion that feels like a video: can you interrupt it?</p>
<p>Real interfaces get used fast. People click a tab, change their mind, click another tab before the first animation finishes. They open a dropdown and close it immediately. They hover in and out of a card in half a second.</p>
<p>If your motion can't handle that, it breaks. A tween that has to finish before the next one starts makes the UI feel laggy, like it's ignoring you. An animation that restarts from the beginning every time looks jumpy.</p>
<p>This is a big reason I lean on springs and layout animations. When you interrupt a spring, it doesn't restart. It takes its current position and velocity and heads toward the new target. The motion stays continuous. If you spam Discrete Tabs, the pills just keep flowing to wherever the active tab currently is. It never feels like it's fighting you.</p>
<p>When I review a component, spamming it is one of the first things I do. If it can't take abuse, it's not done.</p>
<h2>Performance is part of meaning</h2>
<p>Here's something people don't always connect: janky motion means the wrong thing.</p>
<p>If an animation drops frames, it doesn't just look bad. It tells the user the interface is struggling. It makes the product feel slow, even if the actual work is fast. A stuttery transition is worse than no transition, because no transition at least feels instant.</p>
<p>So performance isn't a separate concern from philosophy. It's part of whether the motion communicates what you want.</p>
<p>A few things I keep in mind:</p>
<p><strong>Transforms and opacity are cheap. Layout properties are expensive.</strong> Animating <code>transform</code> and <code>opacity</code> can be handled by the compositor without re-running layout. Animating <code>width</code>, <code>height</code>, <code>top</code>, <code>left</code> directly forces the browser to recalculate layout every frame. Motion's layout animations are smart about this. When you use <code>layout</code> or <code>layoutId</code>, Motion measures the before and after, then animates the difference with transforms. So you get the effect of animating size and position, without paying layout cost every frame.</p>
<p><strong><code>willChange</code> is a hint, not magic.</strong> In Discrete Tabs, several motion elements have <code>style={{ willChange: "transform" }}</code>. That tells the browser to get ready for transform changes, which can smooth things out. But overusing it costs memory, so I only put it on things that genuinely move a lot.</p>
<p><strong>Filters cost more than you think.</strong> Blur is lovely, but it's one of the more expensive things you can animate. I use it in small, short doses, like the tiny 4px blur on the tab label that clears in 200ms. A big blur on a big element running for a long time is going to hurt on lower end devices.</p>
<p><strong>Test on a slow device.</strong> Your laptop is lying to you. Grab an older phone, or use your browser's CPU throttling, and see how the motion holds up. If it stutters, simplify.</p>
<h2>Accessibility and reduced motion</h2>
<p>Some people get motion sick from animations. Some people find movement distracting in a way that makes it hard to focus. Operating systems let users set a preference to reduce motion, and your app should respect it.</p>
<p>Motion makes this pretty approachable. There's a <code>useReducedMotion</code> hook that tells you if the user has that preference on, and there's <code>MotionConfig</code> with a <code>reducedMotion</code> setting that can apply it across your app. Since useLayouts components live in your codebase, you decide how to handle it for your users. Wrapping your app with <code>MotionConfig reducedMotion="user"</code> is a solid default.</p>
<p>But reduced motion doesn't have to mean no feedback. This is where the feedback, focus, flow thinking helps again. If you know what job each animation is doing, you can keep the job and drop the movement. A Status Button can still change color and label to show it's done, without the width animation. A tab can still look active without the slide. The meaning survives. Only the motion goes.</p>
<p>Also, motion should never be the only signal. If the only way to know a tab is active is that it moved, someone who can't see the motion, or has it turned off, is lost. Discrete Tabs shows the active tab with color and a visible label too, not just size. Feedback should be readable even as a still frame.</p>
<p>And keyboard users exist. If a component only feels good with a mouse, it's not done. That's an area I keep working on, honestly, and I'd love help on it from people who know it better than I do.</p>
<h2>Motion is part of your brand</h2>
<p>Something I didn't understand early on: how your product moves is as much a part of its personality as your colors or your fonts.</p>
<p>A product with stiff, quick, precise motion feels efficient. Professional. Maybe a little serious. A product with softer springs and gentler timing feels calm, friendly. A product with lots of overshoot and bounce feels playful, maybe young.</p>
<p>None of these are wrong. But they should be chosen, not accidental. And they should be consistent. If your tabs are snappy and your modals are floaty and your buttons bounce, the product feels like it has three personalities.</p>
<p>This is another reason I give you source instead of a locked package. My springs reflect my taste, which tends toward a slightly weighty, confident feel. Your product might want something different. Since the file is yours, you can tune every component to the same personality. And once you've tuned a few, it's worth pulling your values into a shared file so everything moves the same way.</p>
<h2>How I review a component</h2>
<p>Here's the actual checklist I run through before something goes into useLayouts. It's not formal, it's just what I've ended up doing every time.</p>
<ol>
<li><strong>What's the moment?</strong> Can I name the specific interaction where static UI would feel rude? If not, why does this exist?</li>
<li><strong>What's the job?</strong> For each piece of motion, is it feedback, focus, or flow? Write it down. Anything that's "it looks nice" gets cut.</li>
<li><strong>Does it respond?</strong> Does anything animate without the user doing something? If so, is that on purpose?</li>
<li><strong>Spam test.</strong> Click it twenty times fast. Interrupt it mid animation. Does it stay smooth and continuous?</li>
<li><strong>Slow motion.</strong> Record a video, play it back slowed down. Look for flickers, overlaps, stretched corners, two things fighting over the same space.</li>
<li><strong>Context test.</strong> Put it in a real page, not a white demo. Next to real content, real text, other components. Does it still feel right, or is it too loud?</li>
<li><strong>Slow device.</strong> Throttle the CPU. Does it hold up?</li>
<li><strong>Still frame.</strong> Pause it at the end state. Can you tell what's going on without seeing the motion?</li>
<li><strong>Week test.</strong> Use it in a real project for a while. Does it get annoying? If yes, tone it down or cut it.</li>
<li><strong>Readable code.</strong> Will someone opening the file understand what each part does, so they can change it without breaking it?</li>
</ol>
<p>Number nine has killed more components than all the others combined. Something can pass every other check and still get annoying after a few days of real use. That's when you learn whether motion meant something or was just pretty.</p>
<h2>A closer look at hover</h2>
<p>Hover deserves its own section, because it's probably the most abused moment in web UI. It's also where I made a lot of my early mistakes.</p>
<p>Hover is weird because it's not really an action. The user hasn't decided anything yet. They're just pointing. Sometimes they're pointing on purpose, about to click. A lot of the time they're just moving their mouse across the screen on the way somewhere else.</p>
<p>So hover motion has to work for both cases. It should acknowledge someone who's about to click, and it should stay out of the way of someone who's just passing through.</p>
<p>That's why the default "scale every card up on hover" pattern bugs me so much. When you sweep your cursor across a grid, every card you pass pops up and back down. It's like walking past a row of motion sensor lights. It's acknowledgment nobody asked for.</p>
<p>What I try to do instead:</p>
<p><strong>Keep hover small.</strong> A hover response should be the smallest thing that tells you "this is interactive." A slight shift, a subtle background, a tiny bit of lift. Save the bigger motion for the actual click.</p>
<p><strong>Make hover about something inside.</strong> On cards, I often like the response to happen to something within the card instead of the whole card. The content reacts, not the box. It feels more like you're interacting with what's on the card.</p>
<p><strong>Make the exit fast.</strong> When you move off something, the hover state should leave quickly. Lingering hover states are what make sweeping across a grid feel messy.</p>
<p><strong>Remember touch.</strong> Phones don't have hover. If your component only makes sense with hover, it's broken on mobile. Anything important you show on hover needs another way to reach it.</p>
<p><strong>Use hover to preview, not to perform.</strong> The best hover motion gives you a hint about what'll happen when you click. The Discover Button is a good example of this idea: the hover is a little preview of the button's intent, not a light show.</p>
<p>Hover motion is mostly feedback, with a little focus. It says "yes, you can click this, and here's roughly what'll happen." If it's doing more than that, it's probably decoration.</p>
<h2>Try this on your own app</h2>
<p>You don't need my components to use any of this. Here's an exercise I'd genuinely recommend, and it takes maybe an hour.</p>
<p>Open your app. Go through one real task a user would do, start to finish. Sign up, create something, edit it, delete it, whatever your core flow is. As you go, make two lists.</p>
<p><strong>List one: every place something moves.</strong> Every hover effect, every transition, every fade, every slide. For each one, write down which job it does. Feedback, focus, or flow. If you can't name one, mark it.</p>
<p><strong>List two: every rude moment.</strong> Every place where you did something and the UI didn't acknowledge it right away. Every place where you waited without a sign of life. Every place where the screen changed and you had to re-scan to figure out what happened. Every delete that felt too easy.</p>
<p>Then compare.</p>
<p>Almost every time I've done this, on my own stuff or helping friends with theirs, the result is the same. List one has a bunch of marked items, motion that isn't doing anything. List two has a bunch of moments with no motion at all, where some would really help.</p>
<p>In other words, most apps have motion in the wrong places. Decoration where nothing's needed, and silence where feedback is needed.</p>
<p>The fix is to move your motion budget. Cut the stuff on list one that doesn't have a job. Use that time, and that performance budget, on list two.</p>
<p>Let me walk through what this looks like on a pretty typical app. Imagine a basic project management dashboard. You've seen a hundred of these.</p>
<p><strong>Things that moved:</strong></p>
<ul>
<li>Sidebar items scale on hover. Job? Kind of focus, but every item doing it means none of them stand out. Probably cut, or replace with a subtle background change.</li>
<li>Cards fade up on page load. Job? None really. The user didn't ask for anything. Cut.</li>
<li>Modal slides up from the bottom. Job? Flow, sort of, shows it's a layer on top. Keep, but make it faster.</li>
<li>Charts animate drawing in on load. Job? Arguably focus. But if you visit the dashboard ten times a day, watching the chart draw every time gets old. Make it only happen on first visit, or cut.</li>
</ul>
<p><strong>Rude moments:</strong></p>
<ul>
<li>Clicking "Save" on a task shows nothing until a toast appears in the corner. No feedback at the button. Big one.</li>
<li>Switching between Board, List, and Calendar views just swaps the content. No sense of the switch. Medium.</li>
<li>Deleting a task is an instant red button. No weight, easy to misclick. Big one.</li>
<li>Moving a task to a different column by dragging feels a bit laggy. Medium.</li>
<li>Inline editing a task title just swaps text for an input with no transition. Small, but it happens all the time.</li>
</ul>
<p>Look at that. Four pieces of motion, maybe one doing a real job well. Five rude moments with nothing.</p>
<p>Now you know where to spend your time. A status style save button. A tab switcher that travels between views. A delete with a countdown you can cancel in place. Smoother drag. Inline editing that morphs. That's basically a list of useLayouts categories, which isn't a coincidence, because I made that list by doing exactly this exercise on my own projects.</p>
<pre><code class="language-bash">npx shadcn@latest add @uselayouts/save-button @uselayouts/delete-button @uselayouts/discrete-tabs
</code></pre>
<p>But even if you build these yourself, the exercise is the valuable part. It changes how you see your own UI.</p>
<h2>Objections I hear</h2>
<p>When I talk about this stuff, I get some pushback. Some of it's fair. Here's how I think about the common ones.</p>
<p><strong>"Motion is just polish, we have real features to build."</strong>
I get it. But feedback isn't polish. A save button that doesn't tell you it saved is a usability bug, it's just a quiet one. A delete that's too easy to hit is a data loss risk. Switching views that disorients people slows them down every single time. The rude moments are real costs. They're just hard to see in a bug tracker.</p>
<p><strong>"Users don't notice animations."</strong>
Right. That's the goal. Good motion isn't noticed. Users notice when it's missing, they just don't know that's what they're noticing. They say the app feels "clunky" or "cheap" or "slow" even when it's fast. That's often motion.</p>
<p><strong>"Isn't this all subjective?"</strong>
The exact spring values, yeah, totally subjective. Whether the motion has a job isn't. You can objectively ask: does this tell the user something they'd otherwise miss? That's a question with an answer.</p>
<p><strong>"Our designers already have a motion spec."</strong>
Great. Then use it. Seriously. useLayouts components are files in your project, so you can tune them to match your spec. The philosophy part is about deciding where motion goes. Your spec decides how it feels.</p>
<p><strong>"Won't this slow down my app?"</strong>
Badly done motion can. Well done motion, sticking to transforms and opacity, using layout animations that run on transforms, keeping blur small and short, generally won't. And it can make your app feel faster, because instant feedback makes waits feel shorter even when they aren't.</p>
<h2>Where this philosophy came from</h2>
<p>I didn't read this in a book. It came from shipping a lot of pages that felt dead, and then a lot of pages that felt overdone, and slowly figuring out the difference.</p>
<p>The dead pages had the default kit motion. A scale on hover, a fade on open, the same three transitions on every surface. Technically animated, emotionally flat. The overdone pages had me, excited about springs, putting them on everything until the interface felt drunk.</p>
<p>Somewhere between those two, I started noticing that the stuff that felt right always had a reason. It told me something. It showed me where to look. It kept me oriented. And the stuff that felt wrong, in either direction, didn't.</p>
<p>That's where feedback, focus, and flow came from. They're just the names I gave to the reasons.</p>
<p>It's been really validating to have useLayouts picked for the Vercel Open Source Program Winter 2026 cohort. Not because it proves I'm right about all this, but because it suggests other people think this kind of detail is worth caring about. The support and credits from Vercel mean I can keep spending time on these tiny decisions, like how long a label should blur for, instead of worrying about hosting bills for the docs and registry. That's a weird luxury and I'm grateful for it.</p>
<h2>FAQ</h2>
<p><strong>Do I need to use useLayouts to apply this?</strong>
Not at all. The philosophy works with any animation library, or plain CSS. useLayouts is just my attempt to package components where I've already done this thinking.</p>
<p><strong>What's the one thing I should do first?</strong>
Find your most common user action and make sure it gives instant feedback. Usually that's a save, submit, or primary button. Fixing that one moment does more than any number of hover effects.</p>
<p><strong>Should I remove all decorative motion?</strong>
In a product, I'd cut most of it. On a marketing page or portfolio, you have more room for expression. But even there, ask whether it's helping someone understand something or just showing off.</p>
<p><strong>How do I convince my team?</strong>
Do the audit exercise from this post together. Seeing the two lists side by side is usually more convincing than any argument.</p>
<p><strong>What about scroll animations?</strong>
They're the most overused motion on the web. If scroll motion is helping people understand something, like a step by step explanation, it can be great. If it's just making content fade in, it's mostly slowing people down.</p>
<p><strong>Where do I start with useLayouts?</strong>
Add the registry to your <code>components.json</code>:</p>
<pre><code class="language-json">{
  "registries": {
    "@uselayouts": "https://uselayouts.com/r/{name}.json"
  }
}
</code></pre>
<p>Then add the component for your rudest moment. You can use npm, pnpm, yarn, or bun:</p>
<pre><code class="language-bash">npx shadcn@latest add @uselayouts/save-button
pnpm dlx shadcn@latest add @uselayouts/save-button
yarn dlx shadcn@latest add @uselayouts/save-button
bunx --bun shadcn@latest add @uselayouts/save-button
</code></pre>
<p><strong>Is useLayouts related to UI Layouts?</strong>
No, different projects by different people. Easy mix up.</p>
<h2>The short version</h2>
<p>If you take one thing from this whole long post, take this: every animation should do a job.</p>
<p>Feedback, telling people you heard them. Focus, showing them where to look. Flow, keeping them oriented through change.</p>
<p>If it does one of those, make it fast, make it interruptible, make it respectful of people who prefer less motion, and make it consistent with the rest of your product.</p>
<p>If it doesn't, if it only looks expensive, cut it.</p>
<p>The goal isn't an interface that moves a lot. It's an interface that feels like it's listening.</p>
<p>If you want to see what that looks like in practice, go browse the components at uselayouts.com. Hover, click, spam them, see what holds up. Read the docs intro, it's short. And if any of it ends up in your product, I'd love a star on GitHub. It's at hundreds of stars and climbing, and every one helps someone else stumble onto this way of thinking about motion.</p>
<ul>
<li>Site: <a href="https://uselayouts.com/">https://uselayouts.com/</a></li>
<li>Docs: <a href="https://uselayouts.com/docs/introduction">https://uselayouts.com/docs/introduction</a></li>
<li>GitHub: <a href="https://github.com/iurvish/uselayouts">https://github.com/iurvish/uselayouts</a></li>
</ul>
<p>Thanks for reading all of it. Go cut something.</p>
<p>Urvish (@0xUrvish)</p>
]]></content:encoded></item></channel></rss>