I created this repository to put together all utils and helpers that I need from time to time:
GroupBy
Groups an array of objects by a specific key. From time to time I need to use the newly or not so Object.groupBy(items, callbackFn)
, and the problem was that this method is only supported in newly versions of Node (21.x). I faced this issue after deploying an app at Vercel where the Node version at the time was the 20.x as the newest available or when I was coding a React Native App.
Usage:
const data = [
{ id: 1, category: 'A' },
{ id: 2, category: 'B' },
{ id: 3, category: 'A' },
];
groupBy(data, 'category')
// Result:
// {
// A: [
// { id: 1, category: 'A' },
// { id: 3, category: 'A' },
// ],
// B: [
// { id: 2, category: 'B' },
// ],
// }
Tailwind ClassName Merge
Combines class names into a single string, handling Tailwind CSS class conflicts.
Dependencies:
npm i clsx tailwind-merge
Usage:
<div className={cn('some-classes', 'more classes')} />
Price Formatted to PT-BR
Formats a numeric amount as a currency string in Brazilian Real (BRL).
Usage:
priceFormatted(10000); // '100,00'
priceFormatted(123456, 100); // '1.234,56'
priceFormatted(5000, 1); // '5.000,00'
Generate Slug
Generates a URL-friendly slug from a given string.
Usage:
generateSlug('Hello World!'); // 'hello-world'
generateSlug('Café au lait!'); // 'cafe-au-lait'
generateSlug(' Multiple Spaces '); // 'multiple-spaces'
Is Query Included?
Checks if the query string is included in the stringToCompare after normalization.
Example:
const query1 = 'café';
const stringToCompare1 = 'O café está ótimo';
const result1 = isQueryIncluded(query1, stringToCompare1);
console.log(result1); // true
Example:
const query2 = 'hello';
const stringToCompare2 = ' HeLLo World!';
const result2 = isQueryIncluded(query2, stringToCompare2);
console.log(result2); // true
Example:
const query3 = 'ça';
const stringToCompare3 = 'O café está aqui';
const result3 = isQueryIncluded(query3, stringToCompare3);
console.log(result3); // true
Example:
const query4 = 'world';
const stringToCompare4 = 'Goodbye, everyone!';
const result4 = isQueryIncluded(query4, stringToCompare4);
console.log(result4); // false
Component with 'as' prop
Create custom components with as
prop with TypeScript.
useFormState hook
A custom React hook for managing form state, inspired by React DOM’s useFormState.
- Handles form submissions with async actions
- Manages success, error, and loading states
- Supports automatic form resets
- Supports clearing form state message after a delay, useful for toasts.
- Allows custom success callbacks
foo-form.tsx
'use client'
export function FooForm() {
const [{ success, error, message }, handleSubmit, isSubmitting] = useFormState(
createPageAction,
{
onSuccess() {},
resetFormOnSuccess: false,
resetStateMessage: true,
},
)
useEffect(() => {
if (!success && message) {
toast.error(message, { id: 'foo-action' })
}
if (success && message) {
toast.success(message, { id: 'foo-action' })
}
}, [success, message, isSubmitting])
return (
<form onSubmit={handleSubmit}>
<!-- ... -->
</form>
)
}
foo-action.ts:
'use server'
import { z } from 'zod'
const createFooSchema = z.object({
name: z.string().min(1, 'Enter a name.'),
})
export async function createFooAction(data: FormData) {
const result = createFooSchema.safeParse(Object.fromEntries(data))
if (!result.success) {
const errors = result.error.flatten().fieldErrors
return {
success: false,
message: null,
errors,
}
}
const { name } = result.data
try {
// action
} catch (error) {
return {
success: false,
message: 'An unexpected error occured.',
errors: null,
}
}
return {
success: true,
message: 'Action successfully executed.',
errors: null,
}
}
Convert an entire folder of images to WEBP format
convert-image-directory-to-webp.sh
I was having trouble and wasting my time by converting file by file in command line. This script could help you too:
Requirements:
- This script works on Unix based systems such as MacOS and Linux.
- You'll need
cwebp
command available.
Steps:
- Download
webp-convert-directory.sh
; - Open terminal;
- Access folder containing images;
- Run
sh [file_path]
. You can drag and drop file to terminal to get full path:- Example:
sh /Users/ricardo/Desktop/webp-convert-directory.sh
- Example:
- And voilà! All files converted!
Optional properties on types utility
Make some properties optional on type
type Post {
id: string;
name: string;
category: string;
}
Optional<Post, 'id' | 'category'>
React Native + Expo
Read the Expo Docs on using ESlint and Prettier.
Extra Dependencies:
npm i -D eslint-plugin-simple-import-sort
React 19 + Next.js 15 + ESlint 9
Here is a basic setup with the latest versions of React, Next.js and ESlint.
Prettier Sort imports and exports
That's a great plugin for who always keep reordering and formatting imports and exports. Check it out the plugin repository.
Depependencies:
pnpm add -D @ianvs/prettier-plugin-sort-imports
Setup:
{
"plugins": ["@ianvs/prettier-plugin-sort-imports", "prettier-plugin-sort-json"],
"importOrder": [
"^(react/(.*)$)|^(react$)",
"^(next/(.*)$)|^(next$)",
"<THIRD_PARTY_MODULES>",
"",
"^@/(.*)$",
"^[./]"
],
"importOrderParserPlugins": ["typescript", "jsx", "decorators-legacy"]
}
[!NOTE]
The below plugin was the first wan that I've been using, but recently I discovered a better one.
That's a great plugin for who always keep reordering and formatting imports and exports. Check it out the plugin repository.
Depependencies:
npm i -D eslint-plugin-simple-import-sort
Setup:
{
"plugins": ["simple-import-sort"],
"rules": {
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error"
}
}
Tailwind Prettier Plugin
Checkout the Plugin Docs.
Dependencies:
npm i -D prettier-plugin-tailwindcss
Setup:
// .prettierrc
{
"plugins": ["prettier-plugin-tailwindcss"]
}
Rocketseat Eslint Initial Configs
Dependencies:
npm i -D @rocketseat/eslint-config
Usage:
// [environment]: node, react, next
{
"extends": ["@rocketseat/eslint-config/[environment]"]
}
Add type imports
Configuration:
// .eslintrc.js
{
"rules": {
"@typescript-eslint/consistent-type-imports": [
"error",
{
"prefer": "type-imports"
}
]
}
}
Settings
.vscode/settings.json
: settings for specific projects.
Force to use import aliases:
{
"typescript.preferences.importModuleSpecifier": "non-relative"
}
Setup Tailwind IntelliSense for custom props:
{
"tailwindCSS.classAttributes": ["class", "className", "classNameCenter", ".*Styles"]
}
EditorConfig IDE Plugin
EditorConfig helps maintain consistent coding styles for multiple developers working on the same project across various editors and IDEs. Check it out the tool page. Just need to install a plugin on code editor and set a .editorconfig
file:
Configuration file example:
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
indent_style = tab
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = false
insert_final_newline = false
[*.md]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = false
insert_final_newline = false
- React Haiku: a collection of react hooks and utilities
- Day.js: Day.js is a minimalist JavaScript library that parses, validates, manipulates, and displays dates and times
- Sonner: An opinionated toast component for React. Emil and I share the same last name 🤠.
- Swiper: This is the best slider for websites, web apps, and mobile apps.
- T3 Env: Framework agnostic validation for type-safe environment variables.
- Radix Primitives: Unstyled, accessible, open source React primitives for high-quality web apps and design systems.
- Sharp: High performance Node.js image processing.
- Auth.js: Authentication for the Web.
- TailwindCSS: A utility-first CSS framework.
- Tablr Icons: A package of thousands icons.
- Tanstack React Query: This is a JavaScript library that helps developers fetch, cache, and update data in React applications
- Fancyapps / Fancybox: Fancybox is the ultimate JavaScript lightbox alternative that sets the standard for premium user experience in multimedia display. Supports images, videos, maps, inline content, iframes and any other HTML content.
- KY: Tiny & elegant JavaScript HTTP client based on the Fetch API. Supports experimental next.js cache.
- useDraggableHook: scroll content using mouse events.