# How to Use shadcn/ui Components (Button, Input, Dialog) in refine-shadcn

> Learn to use shadcnui Button Input and Dialog components in refine-shadcn Import directly from @ferdiunal/refine-shadcn/ui for theme awareness and Refine defaults.

- Repository: [Ferdi ÜNAL/refine-shadcn](https://github.com/ferdiunal/refine-shadcn)
- Tags: how-to-guide
- Published: 2026-03-01

---

**Import Button, Input, Dialog, and other shadcn/ui primitives directly from `@ferdiunal/refine-shadcn/ui` to use them with built-in theme awareness and Refine-specific defaults.**

The **ferdiunal/refine-shadcn** repository provides a thin, opinionated wrapper around original shadcn/ui components, enabling seamless integration with the Refine framework. These components ship with Tailwind-based styling, Radix UI primitives, and built-in support for Refine's form handling and theming systems.

## Import Pattern for shadcn/ui Components

All underlying shadcn/ui primitives are re-exported through the `@ferdiunal/refine-shadcn/ui` namespace. The package's `exports` field in [`packages/theme/package.json`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/package.json) maps the `"./ui"` entry to compiled distribution files generated from [`packages/theme/src/ui/index.ts`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/ui/index.ts).

Import components directly from the UI entry point:

```tsx
import { Button, Input, Dialog } from "@ferdiunal/refine-shadcn/ui";

```

This single entry point exposes the full API surface of **Button**, **Input**, **Dialog**, and additional shadcn/ui primitives without requiring separate installations or internal path references.

## Component Architecture and Implementation

Each component in `packages/theme/src/ui/` implements a consistent pattern: Radix UI primitives wrapped with **class-variance-authority** (`cva`) for variant management and the `cn` utility function for conditional class merging.

### Button Component

The **Button** implementation in [`packages/theme/src/ui/button.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/ui/button.tsx) extends the base Radix primitive with Tailwind styling and variant configurations. It supports standard shadcn/ui variants (default, destructive, outline, secondary, ghost, link) plus Refine-specific enhancements for loading states and disabled handling.

Key implementation details:
- Uses `cva` to generate type-safe variant classes
- Forwards refs and all native button attributes
- Integrates with the `ThemeProvider` from [`packages/theme/src/providers/theme-provider.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/providers/theme-provider.tsx)

### Input Component

Located at [`packages/theme/src/ui/input.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/ui/input.tsx), the **Input** wrapper provides a thin abstraction over the native HTML `<input>` element. It forwards all standard attributes while applying consistent styling for focus states, borders, and background colors through the Tailwind configuration.

### Dialog Component

The **Dialog** family in [`packages/theme/src/ui/dialog.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/ui/dialog.tsx) implements a full modal system using `@radix-ui/react-dialog`. This includes **DialogTrigger**, **DialogContent**, **DialogHeader**, **DialogTitle**, **DialogDescription**, **DialogFooter**, and **DialogClose** components.

The implementation adds:
- Built-in animations via Tailwind transitions
- Optional close button visibility via the `showCloseButton` prop
- Backdrop styling consistent with the theme provider

## Practical Usage Examples

### Basic Button with Variants

Create styled buttons using the variant API defined in the source:

```tsx
import { Button } from "@ferdiunal/refine-shadcn/ui";

export const ActionButton = () => (
  <Button
    variant="default"
    size="lg"
    onClick={() => console.log("Action triggered")}
  >
    Execute Action
  </Button>
);

```

The `variant` prop accepts values mapped through the `cva` configuration in [`button.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/button.tsx), while `size` controls padding and height dimensions.

### Input Integration with Refine Forms

Combine **Input** with Refine's **FormField** for type-safe form handling:

```tsx
import { Input } from "@ferdiunal/refine-shadcn/ui";
import { FormField } from "@ferdiunal/refine-shadcn";

export const EmailField = ({ control }) => (
  <FormField
    control={control}
    name="email"
    label="Email Address"
    description="Enter your business email"
  >
    {(field) => (
      <Input 
        type="email" 
        placeholder="user@company.com" 
        {...field} 
      />
    )}
  </FormField>
);

```

The **Input** component forwards all React input props, ensuring compatibility with React Hook Form's field handlers.

### Complete Dialog Implementation

Build accessible modals using the full Dialog compound component pattern:

```tsx
import {
  Dialog,
  DialogTrigger,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
  DialogFooter,
  DialogClose,
} from "@ferdiunal/refine-shadcn/ui";

export const ConfirmDialog = () => (
  <Dialog>
    <DialogTrigger asChild>
      <Button variant="outline">Delete Item</Button>
    </DialogTrigger>

    <DialogContent showCloseButton>
      <DialogHeader>
        <DialogTitle>Confirm Deletion</DialogTitle>
        <DialogDescription>
          This action cannot be undone. The item will be permanently removed from your account.
        </DialogDescription>
      </DialogHeader>

      <DialogFooter>
        <DialogClose asChild>
          <Button variant="secondary">Cancel</Button>
        </DialogClose>
        <Button variant="destructive" onClick={handleDelete}>
          Delete
        </Button>
      </DialogFooter>
    </DialogContent>
  </Dialog>
);

```

The `showCloseButton` prop toggles the visibility of the upper-right close control, while `asChild` on triggers and closes ensures proper composition with button elements.

### Combined Example in a Refine Action

Use all three components together in a create or edit form wrapped in a dialog:

```tsx
import { Button, Input, Dialog } from "@ferdiunal/refine-shadcn/ui";
import { FormField } from "@ferdiunal/refine-shadcn";
import { useForm } from "@refinedev/react-hook-form";

export const CreateRecordModal = () => {
  const { control, handleSubmit } = useForm();

  const onSubmit = (data) => console.log(data);

  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button>Create New Record</Button>
      </DialogTrigger>

      <DialogContent>
        <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
          <FormField 
            control={control} 
            name="title" 
            label="Record Title"
          >
            {(field) => <Input placeholder="Enter title..." {...field} />}
          </FormField>

          <FormField 
            control={control} 
            name="identifier" 
            label="Identifier"
          >
            {(field) => <Input placeholder="ID-123" {...field} />}
          </FormField>

          <div className="flex justify-end gap-2 pt-4">
            <DialogClose asChild>
              <Button variant="outline">Cancel</Button>
            </DialogClose>
            <Button type="submit">Save Record</Button>
          </div>
        </form>
      </DialogContent>
    </Dialog>
  );
};

```

## Summary

- **Import from `@ferdiunal/refine-shadcn/ui`** to access all shadcn/ui primitives compiled from `packages/theme/src/ui/`
- **Components wrap Radix UI primitives** with Tailwind styling via `cva` and the `cn` utility
- **Source files** for Button, Input, and Dialog live in [`packages/theme/src/ui/button.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/ui/button.tsx), [`input.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/input.tsx), and [`dialog.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/dialog.tsx) respectively
- **Theme awareness** is built-in through integration with the `ThemeProvider`
- **Refine compatibility** includes loading states, form field forwarding, and disabled handling patterns

## Frequently Asked Questions

### Do I need to install shadcn/ui separately when using refine-shadcn?

No, all shadcn/ui components are bundled within the `@ferdiunal/refine-shadcn` package. The components are compiled by **tsup** from `packages/theme/src/ui/` into the distribution folder and exposed through the `"./ui"` export in [`packages/theme/package.json`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/package.json). Importing from `@ferdiunal/refine-shadcn/ui` provides the same API without additional dependencies.

### Can I customize the Tailwind classes for these components?

Yes, all components accept a `className` prop that gets merged with base styles through the `cn` utility function. The source files use **class-variance-authority** (`cva`) for variant definitions, allowing you to override or extend the default Tailwind classes. You can also modify the base components directly in `packages/theme/src/ui/` before compilation.

### Are Radix UI primitives exposed directly?

The underlying **Radix UI** primitives (`@radix-ui/react-dialog`, `@radix-ui/react-slot`, etc.) are used internally but not re-exported directly. Instead, they are wrapped with Refine-specific logic and Tailwind styling. If you need direct access to Radix primitives, you would install them separately, though the wrapped versions in refine-shadcn provide all standard Radix functionality plus theme integration.

### How does theme switching work with these components?

Components automatically respond to the **ThemeProvider** defined in [`packages/theme/src/providers/theme-provider.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/theme/src/providers/theme-provider.tsx). The provider manages dark/light mode state and CSS variable injection. Because components use Tailwind's dark mode modifiers and the `cn` utility for class merging, they react dynamically to theme changes without requiring manual configuration per component.