NimUI
Getting Started

Quick Start

Build your first component with Nim UI

This guide will walk you through creating your first functional component using Nim UI.

Your First Component

Let's build a simple login form using Nim UI components.

Login Form Example

Welcome Back

Code
import { Button, Input, Card } from '@nim-ui/components';

export default function LoginForm() {
  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    // Handle login
  };

  return (
    <Card className="w-full max-w-md p-6">
      <h2 className="text-xl font-bold mb-4">Welcome Back</h2>
      <form onSubmit={handleSubmit} className="space-y-4">
        <div>
          <label className="block text-sm font-medium mb-1">Email</label>
          <Input type="email" placeholder="you@example.com" />
        </div>
        <div>
          <label className="block text-sm font-medium mb-1">Password</label>
          <Input type="password" placeholder="••••••••" />
        </div>
        <Button variant="primary" className="w-full">
          Sign In
        </Button>
      </form>
    </Card>
  );
}

Basic Usage Pattern

All Nim UI components follow a consistent pattern:

1. Import the Component

import { Button } from '@nim-ui/components';

2. Use with Props

<Button variant="primary" size="md">
  Click me
</Button>

3. Handle Events

<Button onClick={() => console.log('Clicked!')}>
  Click me
</Button>

Common Patterns

Combining Components

Components work seamlessly together:

Combined Components
Code
<div className="flex items-center gap-3">
  <Input placeholder="Search..." className="flex-1" />
  <Button variant="primary">Search</Button>
</div>

State Management

Use React state naturally:

import { useState } from 'react';
import { Input, Button } from '@nim-ui/components';

export default function SearchBox() {
  const [query, setQuery] = useState('');

  const handleSearch = () => {
    console.log('Searching for:', query);
  };

  return (
    <div className="flex gap-2">
      <Input
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Search..."
      />
      <Button onClick={handleSearch}>Search</Button>
    </div>
  );
}

Customizing with Tailwind

Extend component styles with Tailwind classes:

Custom Styling
Code
<Button
  variant="primary"
  className="rounded-full px-8 shadow-lg"
>
  Custom Button
</Button>

Working with Forms

Build complete forms with proper validation:

import { useState } from 'react';
import { Input, Button, Card } from '@nim-ui/components';

export default function ContactForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    message: '',
  });
  const [errors, setErrors] = useState<Record<string, string>>({});

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();

    // Simple validation
    const newErrors: Record<string, string> = {};
    if (!formData.name) newErrors.name = 'Name is required';
    if (!formData.email) newErrors.email = 'Email is required';
    if (!formData.message) newErrors.message = 'Message is required';

    if (Object.keys(newErrors).length > 0) {
      setErrors(newErrors);
      return;
    }

    // Submit form
    console.log('Form submitted:', formData);
  };

  return (
    <Card className="max-w-md p-6">
      <h2 className="text-xl font-bold mb-4">Contact Us</h2>
      <form onSubmit={handleSubmit} className="space-y-4">
        <div>
          <label className="block text-sm font-medium mb-1">Name</label>
          <Input
            value={formData.name}
            onChange={(e) => setFormData({ ...formData, name: e.target.value })}
            placeholder="John Doe"
          />
          {errors.name && (
            <p className="text-red-500 text-sm mt-1">{errors.name}</p>
          )}
        </div>

        <div>
          <label className="block text-sm font-medium mb-1">Email</label>
          <Input
            type="email"
            value={formData.email}
            onChange={(e) => setFormData({ ...formData, email: e.target.value })}
            placeholder="john@example.com"
          />
          {errors.email && (
            <p className="text-red-500 text-sm mt-1">{errors.email}</p>
          )}
        </div>

        <div>
          <label className="block text-sm font-medium mb-1">Message</label>
          <Input
            value={formData.message}
            onChange={(e) => setFormData({ ...formData, message: e.target.value })}
            placeholder="Your message..."
          />
          {errors.message && (
            <p className="text-red-500 text-sm mt-1">{errors.message}</p>
          )}
        </div>

        <Button type="submit" variant="primary" className="w-full">
          Send Message
        </Button>
      </form>
    </Card>
  );
}

Responsive Design

All components are responsive by default. Use Tailwind breakpoints for custom responsive behavior:

<Button
  className="w-full md:w-auto"
  variant="primary"
>
  Responsive Button
</Button>

Dark Mode Support

Components automatically adapt to dark mode. Enable dark mode in your app:

src/App.tsx
import { useEffect, useState } from 'react';

export default function App() {
  const [darkMode, setDarkMode] = useState(false);

  useEffect(() => {
    if (darkMode) {
      document.documentElement.classList.add('dark');
    } else {
      document.documentElement.classList.remove('dark');
    }
  }, [darkMode]);

  return (
    <div className="min-h-screen bg-white dark:bg-gray-900">
      <button onClick={() => setDarkMode(!darkMode)}>
        Toggle Dark Mode
      </button>
      {/* Your app content */}
    </div>
  );
}

What's Next?

Now that you've built your first component, explore:

Examples

Check out these example projects:

  • E-commerce Store - Full product catalog with cart
  • Dashboard - Admin dashboard with data tables
  • Landing Page - Marketing site with hero and features
  • Authentication - Login, signup, and password reset forms

All examples are available in our GitHub repository.

On this page