A collection of common Javascript and Typescript vim snippets for developing React applications. The snippets within this repo rely on LuaSnip as the snippet provider.
some-typescript-example.mov
Previewing Snippets with coc-snippets
coc-snippets-preview.mov
log-helpers.mov
test-utils.mov
{
"L3MON4D3/LuaSnip",
version = "v2.*",
dependencies = {
+ { "mlaursen/vim-react-snippets", opts = {} },
},Or with additional options:
{
"L3MON4D3/LuaSnip",
version = "v2.*",
dependencies = {
+ {
+ "mlaursen/vim-react-snippets",
+ opts = {
+ readonly_props = true, -- Set to `false` if all props should no longer be wrapped in `Readonly<T>`.
+ test_framework = "@jest/globals", -- Set to "vitest" if you use vitest
+ test_renderer_path = "@testing-library/user-event", -- Set to a custom test renderer. For example "@/test-utils"
+ }
+ },
},Most of the available snippets will be listed below to showcase the generated
code. Tabstops will be indicated with $TABSTOP or $NAME where $NAME is
replaceable. $CFN or $CFN_ will indicate a snippet that uses the current
file name to generate the code.
Some snippets support an "inline" version as where the const whatever = will
be omitted. These snippets will be marked with ✨.
Javascript snippets are not shown since I really only use Typescript now, but they are generally the same without the type definitions included.
- vim-react-snippets
- Typescript Example
- [Previewing Snippets with coc-snippets](#previewing-snippets-with-coc-snippetshttpsgithubcomneoclidecoc-snippets)
- Using Log Helpers
- Writing Tests
- Installation
- Cheatsheet
- Table of Contents
- SCSS Snippets
- Material UI
- Contributing - LuaSnip Template
fce ->
import { type ReactElement, type ReactNode } from "react"
export interface $CFN_Props {
$TABSTOP
children: ReactNode
}
export function $CFN(props: Readonly<$CFN_Props>): ReactElement {
return <></>
}fcde ->
import { type ReactElement, type ReactNode } from "react"
export interface $CFN_Props {
$TABSTOP
children: ReactNode
}
export default function $CFN(props: Readonly<$CFN_Props>): ReactElement {
return <></>
}sfce ->
import { type ReactElement } from "react"
export function $CFN(): ReactElement {
return <></>
}sfcde ->
import { type ReactElement } from "react"
export default function $CFN(): ReactElement {
return <></>
}ffce ->
import { forwardRef, type ReactNode } from "react"
export interface $CFNProps {
$TABSTOP
children: ReactNode
}
export const $CFN = forwardRef<HTML$TABSTOPElement, Readonly<$CFN_Props>>(
function $CFN(props, ref) {
return <div ref={ref}></div>
}
)ffcde ->
import { forwardRef, type ReactNode } from "react"
export interface $CFNProps {
$TABSTOP
children: ReactNode
}
export default forwardRef<HTML$TABSTOPElement, Readonly<$CFN_Props>>(
function $CFN(props, ref) {
return <div ref={ref}></div>
}
)sce ->
import { type ReactElement, type ReactNode } from "react"
export interface $CFN_Props {
$TABSTOP
children: ReactNode
}
export function $CFN(props: Readonly<$CFN_Props>): Promise<ReactElement> {
return <></>
}scde ->
import { type ReactElement, type ReactNode } from "react"
export interface $CFN_Props {
$TABSTOP
children: ReactNode
}
export default function $CFN(
props: Readonly<$CFN_Props>
): Promise<ReactElement> {
return <></>
}sfce ->
import { type ReactElement } from "react"
export function $CFN(): Promise<ReactElement> {
return <></>
}sscde ->
import { type ReactElement } from "react"
export default function $CFN(): Promise<ReactElement> {
return <></>
}useS ->
const [$STATE, set$STATE] = useState$TABSTOP($TABSTOP)useRed ->
const [$STATE, $DISPATCH] = useReducer(function reducer(state: $STATE, action: $ACTION): $STATE {
switch (action.type):
default:
return state
}, $INITIAL_STATE)useE ->
useEffect(() => {
$TABSTOP
}, [])useC ->
const context = useContext($TABSTOP)useCB ->
const $CALLBACK = useCallback(($TABSTOP) => {
$TABSTOP
}, [])useM ->
const $MEMOIZED = useMemo(() => ({
$TABSTOP
}), [])useMR ->
const $MEMOIZED = useMemo(() => {
$TABSTOP
}, [])useR ->
const $REF = useRef$TABSTOP(TABSTOP)ccp ->
import { createContext, useContext } from "react"
export interface $CFN_Context {}
const context = createContext<$CFN_Context | null>(null)
const { Provider } = context
export function use$CFN_Context(): $CFN_Context {
const value = useContext(context)
if (!value) {
throw new Error("$CFN_Context must be initialized.")
}
return value
}useD ->
const dispatch = useAppDispatch()useSL ->
const $VALUE = useSelector(($STATE: AppState) => $SELECTOR)useAS ->
const $VALUE = useAppSelector($STATE)dc ->
const { $TABSTOP } = $PROPSdcuseSomeHook()
^ trigger completion here
const { $TABSTOP } = useSomeHook()edc ->
const { $TABSTOP } = $PROPSif ->
if ($CONDITION) {
$TABSTOP
}else ->
else $TABSTOP{
$TABSTOP
}The if snippet can be triggered from the first tabstop to generate:
else if{
$TABSTOP
}into:
else if ($CONDITION) {
$TABSTOP
}switch ->
switch ($KEY) {
case $VALUE:
$TABSTOP
break
default:
$TABSTOP
}for ->
for (let $I = $0, $I < $LIST.length; $I++) {
const $ITEM = $LIST[$I]
$TABSTOP
}reduce ->
const $VALUE = $LIST.reduce<$TYPE_DEF>(($result, $item) => {
$TABSTOP
return $RESULT
}, $INITIAL)noop ->
const noop = (): void => {
// do nothing
}ro ->
Readonly<$T>intf ->
export interface $CFN_$TABSTOP {
$TABSTOP
}op ->
$NAME?: $STRINGte -> <T $EXTENDS $TABSTOP>
tee -> <E extends HTMLElement = $HTMLElement>
/** ->
/**
* $TABSTOP
*/@e ->
@example $EXAMPLE_NAME
\`\`\`$TSX
$TABSTOP
\`\`\`@d ->
@defaultValue \`$TABSTOP\`@s ->
@since $MAJOR.$MINOR.$PATCH| Shortcut | Nane | Expands to |
|---|---|---|
cl |
Console Log | console.log($TABSTOP) |
clv |
Console Log Variable | console.log("$TABSTOP: ", $TABSTOP) |
ce |
Console Error | console.error($TABSTOP) |
cev |
Console Error Variable | console.error("$TABSTOP: ", $TABSTOP) |
cw |
Console Warn | console.warn($TABSTOP) |
cwv |
Console Warn Variable | console.warn("$TABSTOP: ", $TABSTOP) |
ct |
Console Table | console.table($TABSTOP) |
cd |
Console Debug | console.debug($TABSTOP) |
cdv |
Console Debug Variable | console.debug("$TABSTOP: ", $TABSTOP) |
Note: The logging commands that end in a
vwill have the cursor at the second$TABSTOPinstead of the first so that autocompletion will work.
| Shortcut | Name | Expands to |
|---|---|---|
imp |
Import | import packageName from "package-name" |
impf |
Import File | import File from "./File" |
impd |
Import Destructured | import { destructured } from "package-or/path" |
impp |
Import (Please?) | import "./file" |
icn |
Import Classnames | import cn from "classnames" |
icnb |
Import Cnbuilder | import { cnb } from "cnbuilder" |
ism |
Import SCSS Module | import styles from "./$CFN.module.scss" |
icm |
Import CSS Module | import styles from "./$CFN.module.css" |
| Shortcut | Name | Expands to |
|---|---|---|
exp |
Export | export { default } from "./$CFN" |
expf |
Export File | export $TABSTOP from "./$TABSTOP" |
expd |
Export Destructured | export { $TABSTOP } from "./$TABSTOP" |
expa |
Export All | export * from "$TABSTOP" |
| Shortcut | Expands to |
|---|---|
dev |
process.env.NODE_ENV !== "production" |
prod |
process.env.NODE_ENV === "production" |
desc ->
describe('$CFN', () => {
it('should $TABSTOP', () => {
$TABSTOP
)}
})it ->
it("should $TABSTOP", () => {
$TABSTOP
})ita ->
it("should $TABSTOP", async () => {
$TABSTOP
})NOTE: when using
vitest,toThrowError()will be used instead oftoThrow()
| Shortcut | Name | Expands to |
|---|---|---|
es |
Expect Snapshot | expect(${container}).toMatchSnapshot() |
ett |
Expect To Throw | expect(() => $TABSTOP).toThrow() |
entt |
Expect Not To Throw | expect(() => $TABSTOP).not.toThrow() |
enc |
Expect Not Called | expect($TABSTOP).not.toHaveBeenCalled() |
ecw |
Expect Called With | expect($TABSTOP).toHaveBeenCalledWith($TABSTOP) |
encw |
Expect Not Called With | expect($TABSTOP).not.toHaveBeenCalledWith($TABSTOP) |
ect |
Expect Called Times | expect($TABSTOP).toHaveBeenCalledTimes($TABSTOP) |
| Shortcut | Name | Expands to |
|---|---|---|
sgbr |
Screen Get By Role | const $TABSTOP = screen.getByRole("${button}", { name: "$TABSTOP" }) |
sgbru |
Screen Get By Role (Unnamed) | const $TABSTOP = screen.getByRole("${progressbar}") |
sgbi |
Screen Get By testId | const $TABSTOP = screen.getByTestId("$TABSTOP") |
sgbt |
Screen Get By Text | const $TABSTOP = screen.getByText("$TABSTOP") |
sgbl |
Screen Get By Label Text | const $TABSTOP = screen.getByLabelText("$TABSTOP") |
sfbr |
Screen Find By Role | const $TABSTOP = await screen.findByRole("${button}", { name: "$TABSTOP" }) |
sfbru |
Screen Find By Role (Unnamed) | const $TABSTOP = await screen.findByRole("${progressbar}") |
fbi |
Screen Find By testId | const $TABSTOP = await screen.findByTestId("$TABSTOP") |
fbt |
Screen Find By Text | const $TABSTOP = await screen.findByText("$TABSTOP") |
fbl |
Screen Find By Label Text | const $TABSTOP = await screen.findByLabelText("$TABSTOP") |
gbr |
Get By Role | const $TABSTOP = getByRole("${button}", { name: "$TABSTOP" }) |
gbru |
Get By Role (Unnamed) | const $TABSTOP = getByRole("${progressbar}") |
gbi |
Get By testId | const $TABSTOP = getByTestId("$TABSTOP") |
gbt |
Get By Text | const $TABSTOP = getByText("$TABSTOP") |
fbr |
Find By Role | const $TABSTOP = await findByRole("${button}", { name: "$TABSTOP" }) |
fbru |
Find By Role (Unnamed) | const $TABSTOP = await findByRole("${progressbar}") |
fbi |
Find By testId | const $TABSTOP = await findByTestId("$TABSTOP") |
fbt |
Find By Text | const $TABSTOP = await findByText("$TABSTOP") |
rtf ->
import { render, screen, userEvent } from "${@testing-library/react}"
import { $CFN } from "../$CFN"
describe("$CFN", () => {
it("should $TABSTOP", () => {
$TABSTOP
})
})rtfe ->
import { render, screen, userEvent } from "${@testing-library/react}"
import { $CFN } from "../$CFN.js"
describe("$CFN", () => {
it("should $TABSTOP", () => {
$TABSTOP
})
})gtf ->
import { describe, expect, it } from "${@jest/globals}"
import { render, screen, userEvent } from "${@testing-library/react}"
import { $CFN } from "../$CFN"
describe("$CFN", () => {
it("should $TABSTOP", () => {
$TABSTOP
})
})gtfe ->
import { describe, expect, it } from "${@jest/globals}"
import { render, screen, userEvent } from "${@testing-library/react}"
import { $CFN } from "../$CFN.js"
describe("$CFN", () => {
it("should $TABSTOP", () => {
$TABSTOP
})
})uet ->
it("should $TABSTOP", async () => {
const user = userEvent.setup()
$TABSTOP
expect(true).toBe(true)
})wf ->
await waitFor(() => {
$TABSTOP
})| Shortcut | Name | Expands to |
|---|---|---|
use |
Use | @use "$TABSTOP"; |
use* |
Use * | @use "$TABSTOP" as *; |
for |
Forward | @forward "$TABSTOP" with ($TABSTOP); |
pcs |
Prefers Color Scheme | @media (prefers-color-scheme: $DARK) { $TABSTOP } |
fun ->
@function $TABSTOP($TABSTOP) {
$TABSTOP
@return $TABSTOP;
}mix ->
@mixin $TABSTOP($TABSTOP) {
$TABSTOP
}conf ->
@mixin configure($$TABSTOP: null) {
@if $1 {
$-$1: $1 !global;
}
$TABSTOP
}sg ->
@if $$TABSTOP {
$-$1: $1 !global;
}sa ->
$$name: $NULL;sa ->
$$name: $NULL;if ->
if(sass($CONDITION): $THEN; else: $THAT)| Shortcut | Name | Expands To |
|---|---|---|
mg |
Map Get | map.get($$TABSTOP, $TABSTOP) |
ms |
Map Set | map.set($$TABSTOP, $TABSTOP) |
mr |
Map Remove | map.remove($$TABSTOP, $TABSTOP) |
mm |
Map Merge | map.merge($$TABSTOP, $TABSTOP) |
mdm |
Map Deep Merge | map.deep-merge($$TABSTOP, $TABSTOP) |
la |
List Append | list.append($$TABSTOP, $TABSTOP) |
li |
List Index | list.index($$TABSTOP, $TABSTOP) |
ll |
List Length | list.length($$TABSTOP) |
ln |
List Nth | list.nth($$TABSTOP, $TABSTOP) |
to |
Meta type-of | meta.type-of($$TABSTOP) |
si |
String Index | string.index($$TABSTOP, $TABSTOP) |
sl |
String Length | string.length($$TABSTOP) |
sn |
String Slice | string.slice($$TABSTOP, $TABSTOP, $TABSTOP) |
su |
String Unquote | string.unquote($TABSTOP) |
sx ->
sx={(theme) => ({
$TABSTOP
})}local ls = require("luasnip")
local s = ls.snippet
local sn = ls.snippet_node
local isn = ls.indent_snippet_node
local t = ls.text_node
local i = ls.insert_node
local f = ls.function_node
local c = ls.choice_node
local d = ls.dynamic_node
local r = ls.restore_node
local events = require("luasnip.util.events")
local ai = require("luasnip.nodes.absolute_indexer")
local extras = require("luasnip.extras")
local l = extras.lambda
local rep = extras.rep
local p = extras.partial
local m = extras.match
local n = extras.nonempty
local dl = extras.dynamic_lambda
local fmt = require("luasnip.extras.fmt").fmt
local fmta = require("luasnip.extras.fmt").fmta
local conds = require("luasnip.extras.expand_conditions")
local postfix = require("luasnip.extras.postfix").postfix
local types = require("luasnip.util.types")
local parse = require("luasnip.util.parser").parse_snippet
local ms = ls.multi_snippet
local k = require("luasnip.nodes.key_indexer").new_key