EmpireUI
Get Pro
← Blog7 min read#vscode#react#snippets

VS Code React Snippets: Custom Templates That Save Hours

Stop retyping the same boilerplate. Custom VS Code React snippets cut hours off your workflow — here's how to build templates that actually match the way you code.

VS Code editor open with React component code on a dark screen

Why the Built-In Snippets Never Quite Fit

Honestly, the default React snippets extensions in the VS Code marketplace are fine — until they're not. You install something like ES7+ React/Redux Snippets, type rfce, and get a functional component that uses export default at the bottom. But you want named exports. And you want props typed with TypeScript. And you want a Tailwind className already on the wrapper div. The generated boilerplate fights you more than it helps.

This is the core problem with generic snippet packs: they're written for the median developer, not for you. Your project has opinions — on naming conventions, on how you structure components, on whether you're using React.FC or plain function signatures. Generic snippets ignore all of that.

Writing your own takes maybe 20 minutes the first time. After that it's muscle memory. You'll wonder why you didn't do it two years ago.

How VS Code User Snippets Actually Work

Open the command palette (Cmd+Shift+P on Mac, Ctrl+Shift+P on Windows/Linux) and search for "Snippets: Configure User Snippets". You'll see options to create global snippets or per-language files. For React work, pick typescriptreact.json — that covers .tsx files. If you also write plain .jsx, add one for javascriptreact.json.

Each snippet is a JSON object with four fields: prefix (what you type to trigger it), body (an array of strings, one per line), description (shown in the autocomplete tooltip), and an optional scope. Inside body, you use $1, $2, etc. for tab stops — cursor positions you jump between with Tab. $0 is the final resting position. ${1:placeholder} gives a tab stop with default text you can overwrite.

Variables like $TM_FILENAME_BASE inject the current filename without extension. That one alone is worth knowing — it means your component name auto-populates from whatever you named the file.

A Production-Ready React Component Snippet

Here's the snippet I actually use every day. It generates a typed functional component with a cn utility import (for Tailwind class merging), a typed props interface, and a sensible structure. The tab stops let you fill in the component name, extend the props, and then write the JSX body — all without touching your mouse.

// typescriptreact.json
{
  "React Typed FC": {
    "prefix": "rfc",
    "description": "Typed React functional component with Tailwind",
    "body": [
      "import { cn } from '@/lib/utils'",
      "",
      "interface ${1:$TM_FILENAME_BASE}Props {",
      "  className?: string",
      "  ${2:children?: React.ReactNode}",
      "}",
      "",
      "export function ${1:$TM_FILENAME_BASE}({ className, ${3:children} }: ${1:$TM_FILENAME_BASE}Props) {",
      "  return (",
      "    <div className={cn('${4:relative flex flex-col}', className)}>",
      "      ${3:children}",
      "    </div>",
      "  )",
      "}",
      "$0"
    ]
  }
}

Notice $TM_FILENAME_BASE appears three times as the default for $1. The first time you tab in, you're editing the component name — and all three instances update simultaneously. That's the linked tab stop feature. Change CardHeader to ModalFooter and it propagates everywhere in one keystroke.

Snippets for Tailwind Patterns You Repeat Constantly

Beyond full components, the real time savings come from snippets for the small patterns you type dozens of times a day. Things like a flex container with a gap, a glassmorphism card (if you're into that — check out what glassmorphism actually is before you reach for it), or a responsive grid. These aren't component-level snippets — they're inline JSX snippets that autocomplete inside an existing return statement.

// Glassmorphism container snippet
"Glass Card": {
  "prefix": "glasscard",
  "description": "Glassmorphism card wrapper",
  "body": [
    "<div",
    "  className={cn(",
    "    'rounded-2xl border border-white/10 bg-white/5 p-${1:6} backdrop-blur-${2:md}',",
    "    'shadow-[0_8px_32px_rgba(0,0,0,0.24)]',",
    "    className",
    "  )}",
    ">",
    "  $0",
    "</div>"
  ]
}

That shadow-[0_8px_32px_rgba(0,0,0,0.24)] is a specific value — not a generic shadow class. Tailwind v4.0.2 lets you do arbitrary shadow values inside brackets, and having them captured in a snippet means you're not recalculating or guessing every time. If you want to experiment with shadow values before committing them to a snippet, the box shadow CSS guide covers the syntax thoroughly.

Theme-Aware Snippet Patterns for Dark Mode

Here's the thing: a lot of component snippets break down the moment you're building for both light and dark mode. You end up with hardcoded bg-white classes scattered everywhere, then spend 20 minutes doing find-and-replace when the design switches to a dark theme. The fix is baking the dark-mode variant directly into your snippet's default classes.

A pattern I've settled on is structuring default className strings with the light variant first, then the dark override inline — 'bg-white dark:bg-zinc-900'. If you're using theme toggling in React with a class-based strategy (where .dark is added to <html>), this just works out of the box in Tailwind without any extra configuration.

Add a tab stop at position $3 after the dark-mode class so you can immediately append more classes without navigating there manually. Small thing, saves a second each time. Across 50 components a day, that adds up.

Organizing Snippets With Prefixes That Don't Collide

You'll run into prefix conflicts fast if you're not careful. Type rc and VS Code might offer 12 different completions. The trick is namespacing — use a short consistent prefix pattern per category. I use r for React structure snippets, tw for Tailwind layout patterns, h for hook skeletons, and t for TypeScript type helpers.

So rfc is a typed functional component. rfcf is the same thing but with a forwardRef wrapper. twflex drops in a flex container with an 8px gap (which in Tailwind is gap-2). hstate gives you a useState with a typed initial value and a labeled setter. Keep your prefixes short but memorable.

If you're on a team, consider committing a shared .vscode/snippets/ directory to the repo with a typescriptreact.json inside. VS Code picks up workspace-level snippets automatically. Everyone gets the same patterns — no more "how did you generate that component so fast" questions in Slack.

Snippet Scoping and When to Use Project-Level vs Global

Global snippets live in ~/Library/Application Support/Code/User/snippets/ (Mac) or %APPDATA%\Code\User\snippets\ (Windows). They're available in every project, every workspace. That's great for truly universal patterns — bare useState, typed useEffect, a console.log with a label prefix. Stuff that's the same regardless of what you're building.

Project-level snippets (.vscode/typescriptreact-snippets.json) should hold the opinionated stuff — your specific cn import path, your design system's component structure, Tailwind classes that reflect your project's spacing scale. If you're using Empire UI's component patterns, for example, you'd want snippets that match those structural conventions rather than some generic component shape.

What about using both at once? You can. VS Code merges them, with workspace snippets taking precedence when there's a prefix collision. So you can have a global rfc that generates a minimal component, and override it per-project with a richer version that knows about your specific imports and folder structure. Why wouldn't you use that?

Pairing Snippets With Empire UI Components

If you're pulling components from Empire UI — or building on top of its 40 visual styles — snippets become even more useful as a companion layer. You can create snippets that scaffold the exact prop shapes for components you use most. A snippet for a GlassCard component import and usage, a snippet for the gradient button pattern, a snippet for the sidebar layout structure.

The time this saves isn't just in typing. It's in cognitive load. You're not context-switching to documentation to remember prop names — the snippet shows you the shape via tab stops and placeholder text. Combined with tools like the gradient generator for picking your color values and the glassmorphism generator for nailing your blur and opacity values, you end up with a feedback loop that's tight: generate a value in the tool, paste it into a snippet, never think about it again.

That's the actual productivity win. Not typing faster. Thinking less about the mechanical parts so you can think more about the parts that actually matter.

FAQ

Where do I find my VS Code user snippets file for TypeScript React?

Open the command palette with Cmd+Shift+P (Mac) or Ctrl+Shift+P (Windows/Linux), search for 'Snippets: Configure User Snippets', then select 'typescriptreact' from the list. This opens a JSON file at ~/Library/Application Support/Code/User/snippets/typescriptreact.json on Mac.

Can I share snippets with my team via version control?

Yes. Create a .vscode/ directory in your project root and add a file named typescriptreact-snippets.json (or javascriptreact-snippets.json). VS Code picks these up automatically. Commit the file to your repo and every team member gets the same snippets when they open the workspace.

How do I make a tab stop reuse the same value in multiple places?

Use the same number for all the positions that should mirror each other. For example, if you want the component name to appear in the interface name, function name, and prop type annotation, use $1 (or ${1:DefaultName}) in all three spots. When you type the name once, all three update simultaneously.

Are VS Code snippets the same as Emmet abbreviations?

No — they're different systems. Emmet is specifically for HTML/JSX tag expansion and uses a CSS-selector-like syntax. VS Code user snippets are JSON-defined templates for any arbitrary code pattern, with tab stops, placeholders, and variable injection. You can use both at the same time; they don't conflict.

My snippet prefix conflicts with an existing suggestion. How do I fix it?

Rename your prefix to be more specific. A common approach is namespacing: prefix all your custom snippets with a short project abbreviation or category code like 'eu' (for Empire UI) or 'tw' for Tailwind patterns. This avoids collisions with built-in IntelliSense suggestions and third-party snippet extensions.

Can snippets import from different paths depending on the file location?

Not natively — VS Code snippets don't have conditional logic. The workaround is to use the $TM_RELATIVE_FILEPATH variable to check your location, but it only works as a value, not a condition. For path-sensitive imports, most teams standardize on absolute alias paths (like @/components/) so the import is always the same regardless of file depth.

Free components in 40 styles
React & Tailwind, copy-paste ready.
Browse →

Read next

Best VS Code Extensions for React Developers in 2026Prettier Configuration: Format on Save for React + TypeScriptReact UI Components Complete Reference: 60+ Patterns with CodeBuilding Design Systems That Scale: Engineering Guide 2026