Open In App

Create Command Palettes UI using Next.JS and Tailwind CSS

Last Updated : 14 Oct, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

A command palette is a user interface element that allows users to easily access and execute commands or functions in an application. we will build a command palette UI using Next.js as the framework Tailwind CSS for styling and React Icons for adding interactive icons.

A command palette is essentially a search bar that allows users to type in commands and quickly see a list of matching actions that can be executed. This functionality makes it easier for both novice and power users to interact with software and improves usability and overall efficiency.

Preview Image

out78

Prerequisites

Steps to create and Configure the project

Here we will create a sample Next JS project then we will install Tailwind CSS once it is completed we will start development for Command Palettes UI using Next js and Tailwind CSS. Below are the steps to create and configure the project.

Step 1: Set up a React Application

First, create a sample Next JS application by using the mentioned command then navigate to the project folder.

npm create next-app
cd next-app

Project Structure:

Screenshot-2024-10-05-201702
Project Structure

Updated Dependencies:

  "dependencies": {
"next": "14.2.8",
"react": "^18",
"react-dom": "^18",
"react-icons": "^5.3.0"
},

Step 2: Install and Configure Tailwind CSS

Once Project is created successfully Now install and configure the Tailwind css by using below commands in your project.

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

Step 3: Develop Business logic

Once Tailwind css installation and configuration is completed. Now we need to develop user interface for Command Palettes UI using tailwind CSS and for making it responsive.

  • src\app\page.tsx
  • src\app\globals.css
  • tailwind.config.ts

Example: This demonstrates the creation of Command Palettes UI using Next js and Tailwind CSS:

CSS
@tailwind base;
@tailwind components;
@tailwind utilities;

:root {
  --background: #ffffff;
  --foreground: #171717;
}

@media (prefers-color-scheme: dark) {
  :root {
    --background: #0a0a0a;
    --foreground: #ededed;
  }
}

body {
  color: var(--foreground);
  background: var(--background);
  font-family: Arial, Helvetica, sans-serif;
}

@layer utilities {
  .text-balance {
    text-wrap: balance;
  }
}
JavaScript
'use client';

import React, { useState } from 'react';
import { FaSearch, FaTimes } from 'react-icons/fa';

const commands = [
    { name: 'New File', description: 'Create a new file' },
    { name: 'Open File', description: 'Open an existing file' },
    { name: 'Save', description: 'Save the current file' },
    { name: 'Close', description: 'Close the application' },
];

export default function Home() {
    const [isOpen, setIsOpen] = useState(false);
    const [query, setQuery] = useState('');
    const [activeIndex, setActiveIndex] = useState(0);

    const filteredCommands = commands.filter(command =>
        command.name.toLowerCase().includes(query.toLowerCase())
    );

    const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
        if (e.key === 'ArrowDown') {
            setActiveIndex((prevIndex) => (prevIndex + 1) % filteredCommands.length);
        } else if (e.key === 'ArrowUp') {
            setActiveIndex((prevIndex) => (prevIndex - 1 + 
            filteredCommands.length) % filteredCommands.length);
        } else if (e.key === 'Enter') {
            if (filteredCommands.length > 0) {
                alert(`Executing: ${filteredCommands[activeIndex]?.name}`);
                setQuery('');
                setIsOpen(false);
            }
        }
    };

    return (
        <div className="min-h-screen flex items-center 
                        justify-center bg-gray-100">
            <button
                onClick={() => setIsOpen(true)}
                className="p-2 bg-green-500 text-white rounded">
                Open Command Palette
            </button>

            {isOpen && (
                <div className="absolute top-1/4 left-1/2 transform -translate-x-1/2
                                 w-1/3 bg-white shadow-lg rounded-lg p-4 z-50">
                    <div className="flex items-center">
                        <FaSearch className="text-gray-400 mr-2" />
                        <input
                            type="text"
                            placeholder="Type a command..."
                            value={query}
                            onChange={(e) => setQuery(e.target.value)}
                            onKeyDown={handleKeyDown}
                            className="flex-1 border border-gray-300 rounded p-2" />
                        <button onClick={() => setIsOpen(false)} className="ml-2">
                            <FaTimes className="text-gray-500" />
                        </button>
                    </div>

                    <ul className="mt-2 max-h-60 overflow-y-auto">
                        {filteredCommands.map((command, index) => (
                            <li
                                key={command.name}
                                className={`p-2 rounded cursor-pointer ${
                                    index === activeIndex
                                        ? 'bg-blue-100'
                                        : 'hover:bg-gray-100'
                                }`}
                                onMouseEnter={() => setActiveIndex(index)}
                                onClick={() => {
                                    alert(`Executing: ${command.name}`);
                                    setQuery('');
                                    setIsOpen(false);
                                }}>
                                <div className="font-bold">{command.name}</div>
                                <div className="text-gray-500">{command.description}</div>
                            </li>
                        ))}
                    </ul>
                </div>
            )}
        </div>
    );
}
JavaScript
import type { Config } from "tailwindcss";

const config: Config = {
  content: [
    "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
  ],
  theme: {
    extend: {
      colors: {
        background: "var(--background)",
        foreground: "var(--foreground)",
      },
    },
  },
  plugins: [],
};
export default config;

Step 4: Run the Application

Once Development is completed Now we need run the next js application by using below command. By default the next js application run on port number 3000.

npm run dev

Output: Once Project is successfully running then open the below URL to test the output.

http://localhost:3000/

Conclusion

By following this article you have successfully created a command palette UI using Next.js and Tailwind CSS and React Icons. This approach can be further customized with more functionalities like key binding to trigger commands and filtering commands or adding animation. The flexibility of Tailwind CSS and the simplicity of React Icons make it easy to scale and modify the component for other purposes in your projects.


Next Article
Article Tags :

Similar Reads