tent ui vs Building Custom Components: When to Use a Library
A practical guide to the build-vs-buy decision for React UI components. When does building custom components make sense, and when should you reach for a library like tent ui?
Every frontend team eventually asks the same question: should we build this component ourselves, or use a library?
The honest answer is: it depends. But the factors that should inform that decision are often misunderstood. Teams overbuild things that should be installed in one command, and they over-rely on libraries for things that are truly unique to their product.
This is a framework for making that call — and an honest look at where a library like tent ui fits.
The Real Cost of Building Custom
When a developer says "I'll just build it," they are usually thinking about the initial implementation time. That is the wrong number.
The real cost of a custom component includes:
- Initial implementation (the part teams think about)
- Cross-browser QA (Safari, Firefox, mobile WebKit)
- Accessibility audit (ARIA, keyboard nav, screen reader testing)
- Edge cases (empty states, loading states, error states, overflow behavior)
- Responsive design (from 320px to 2560px)
- Dark mode support (if your app has it)
- Ongoing maintenance (dependency updates, bug fixes, breaking changes in dependent libraries)
- Documentation (so the next engineer knows how to use it)
- Testing (unit tests, integration tests, visual regression)
A component that looks like a 2-hour build often costs 2-3 days to do properly. Most teams underestimate this by a factor of 4-5x.
The Real Cost of Using a Library
Library components have their own costs:
- Bundle overhead — even tree-shaken components add bytes
- Customization limits — the component might do 80% of what you need, and the remaining 20% requires fighting the library's API
- Dependency risk — the library might be abandoned, have security vulnerabilities, or change its API
- Learning curve — your team needs to understand the library's patterns and conventions
These costs are real. The question is whether they are smaller than the build cost.
A Simple Decision Framework
Ask these four questions:
1. Is this component truly unique to your product?
If the answer is yes, you probably need to build it. A custom data visualization specific to your domain, a specialized workflow step in your product's core flow, a component that embeds your proprietary data model — these are things a generic library cannot express.
If the answer is no — if this is a button, a date picker, a copy-to-clipboard button, a file tree, a toast — then you are reinventing something that has been solved well many times.
2. Does this component require deep domain knowledge of your data?
If the component needs to understand your specific data model, query patterns, or business logic, it probably should not live in a generic component library anyway.
// This probably belongs in YOUR codebase — it knows about YOUR data model
function UserActivityHeatmap({ userId }: { userId: string }) {
const { data } = useUserActivity(userId); // your custom hook
return <Heatmap data={transformForHeatmap(data)} />;
}
// But the underlying Heatmap visualization might be a library component
// The data transformation is yours; the rendering primitive can be borrowed3. What is the maintenance burden?
For a startup with 3 frontend engineers, maintaining a custom accessible DatePicker is a real tax. Browser quirks, mobile keyboard behavior, timezone handling, locale formatting — these edge cases accumulate.
For a 50-person design system team, building custom is viable because you have the bandwidth to maintain it properly.
Rule of thumb: If you cannot afford a dedicated 0.5 FTE to maintain a component over time, lean toward using a library.
4. How often will this component change?
Components that are stable and foundational (Button, Input, Dialog) benefit from library stability. Components at the intersection of rapid product iteration often need to be in your codebase where they can evolve quickly.
Where Libraries Like tent ui Fit
tent ui is specifically designed for components that are:
- Genuinely non-trivial to build correctly — the WorldMap component, for example, handles SVG path calculations, projection math, and animation with Framer Motion
- Truly non-unique — a copy-to-clipboard button does not differentiate your product; it is plumbing
- Stable enough to use as a dependency — once you install it, it should just work
// Don't build this yourself — clipboard API has edge cases across iOS/Android
// and the visual feedback state is more work than it looks
import { CopyButton } from "@/components/ui/copy-button";
// tent ui handles: clipboard API normalization, fallback for older browsers,
// visual feedback state machine (idle → copied → reset), timeout cleanup
function CodeBlock({ code }: { code: string }) {
return (
<div className="relative">
<pre>{code}</pre>
<CopyButton value={code} className="absolute top-2 right-2" />
</div>
);
}Compare that to a naive implementation that most teams reach for:
// What most teams write initially — looks simple, breaks in edge cases
function NaiveCopyButton({ value }: { value: string }) {
const [copied, setCopied] = useState(false);
const copy = () => {
navigator.clipboard.writeText(value); // throws on insecure origins
setCopied(true);
setTimeout(() => setCopied(false), 2000);
// Bug: if user clicks again during timeout, state resets incorrectly
// Bug: no error handling for clipboard permission denial
// Bug: no visual loading state for async clipboard operations
// Not accessible: no aria-label change when state changes
};
return <button onClick={copy}>{copied ? "Copied!" : "Copy"}</button>;
}The naive version has at least 4 bugs. The tent ui version handles all of them.
Components Worth Building Yourself
Some things genuinely belong in your codebase:
Data visualizations tied to your domain. If you are building a financial dashboard, your candlestick chart understands your specific data schema, color conventions, and interaction patterns. A generic library component is a poor fit.
Multi-step workflows. Your checkout flow, onboarding wizard, or settings migration process is specific to your product's state machine and business rules.
Brand-specific decorative elements. Your logo animation, custom loading spinner, or mascot component is yours.
Components that integrate deeply with your state management. If a component needs to read from a specific Jotai/Zustand/Redux slice, it belongs in your codebase.
// This belongs in your codebase — it's your product's specific flow
function OnboardingWizard() {
const [step, setStep] = useOnboardingState(); // your store
const { user } = useAuth(); // your auth system
return (
<WizardContainer>
{step === "profile" && <ProfileStep userId={user.id} onNext={() => setStep("preferences")} />}
{step === "preferences" && <PreferencesStep onNext={() => setStep("complete")} />}
{step === "complete" && <CompletionStep />}
</WizardContainer>
);
}The tent ui Component-by-Component Analysis
Here is an honest assessment of whether each tent ui component is "worth building" vs. worth installing:
A Practical Recommendation
Start with a simple rule: if the component exists in shadcn/ui or a shadcn-compatible registry, and if it does 95%+ of what you need, use the library component.
For the 5% customization, shadcn-pattern libraries (including tent ui) give you the source code — you are not fighting an opaque API. You can modify the component directly once it is in your repo:
# Install the component — now it's YOUR code
npx shadcn@latest add https://ui.srb.codes/r/copy-button.json
# Modify it directly in your codebase
# No forking, no monkey-patching, no `!important` overridesThis distribution model removes the main downside of using a library: you are never stuck with something that does not fit. Install it, customize it, own it.
Conclusion
The build-vs-buy decision in frontend comes down to:
- How unique is this component to your product? More unique → more reason to build.
- What is the true maintenance cost? More complex edge cases → more reason to use a library.
- How much do you own the code? Libraries that give you the source (like tent ui) collapse the distinction.
The old framing of "use a library" vs. "build your own" is less relevant when the library gives you the source code as a starting point. You are always building — you are just choosing whether to start from zero or from a working, tested baseline.
For the components in tent ui, the calculus is clear: the baseline is worth installing.
Browse all components at ui.srb.codes/docs/components.