# Shadcn Admin Kit
Shadcn Admin Kit is a modern React component library for building admin interfaces with minimal boilerplate. Built on top of shadcn/ui and ra-core (React-Admin core), it provides a comprehensive set of components for creating full-featured CRUD applications with authentication, data tables, forms, and relationship management. The library combines the accessibility and aesthetics of Radix UI with the battle-tested admin framework patterns from React-Admin, all styled with Tailwind CSS.
The kit is designed to work with any backend API (REST, GraphQL, or custom protocols) through data provider adapters. It includes intelligent guessers that scaffold code automatically based on your API responses, making it quick to prototype admin interfaces. With full TypeScript support, built-in responsive design, internationalization capabilities, and dark mode support, it accelerates admin application development while maintaining flexibility for customization.
## Admin Component
Root application component that configures data provider, authentication, routing, and theming.
```tsx
import { Admin, Resource } from "@/components/admin";
import simpleRestProvider from 'ra-data-simple-rest';
import { authProvider } from './authProvider';
import { ProductList, ProductEdit, ProductCreate } from './products';
import { Dashboard } from './dashboard';
const dataProvider = simpleRestProvider('https://api.example.com');
export const App = () => (
record.name}
/>
);
```
## List Component
Displays paginated, sortable, and filterable lists of records with create and export actions.
```tsx
import { List, DataTable, TextInput, SelectInput, ReferenceInput, AutocompleteInput } from "@/components/admin";
const filters = [
,
,
];
export const ProductList = () => (
);
```
## Edit Component
Provides a form interface for editing existing records with automatic data loading and saving.
```tsx
import { Edit, SimpleForm, TextInput, NumberInput, ReferenceInput, AutocompleteInput, BooleanInput } from "@/components/admin";
import { required, minValue, maxValue } from "ra-core";
export const ProductEdit = () => (
);
```
## Create Component
Form interface for creating new records with validation and redirect options.
```tsx
import { Create, SimpleForm, TextInput, NumberInput, ReferenceInput, AutocompleteInput } from "@/components/admin";
import { required, minValue } from "ra-core";
export const ProductCreate = () => (
}
/>
);
```
## Show Component
Displays a single record in read-only mode with customizable field layout.
```tsx
import { Show, SimpleShowLayout, TextField, NumberField, ReferenceField, DateField, BooleanField } from "@/components/admin";
export const ProductShow = () => (
);
```
## DataTable Component
Advanced data table with sorting, column visibility, bulk actions, and row navigation.
```tsx
import { List, DataTable, ReferenceField, TextField, NumberField, DateField, BulkDeleteButton, BulkExportButton } from "@/components/admin";
export const OrderList = () => (
>
}
>
(
{record.status}
)}
/>
);
```
## SimpleForm Component
Form wrapper with integrated validation, error handling, and toolbar.
```tsx
import { Edit, SimpleForm, TextInput, SaveButton, DeleteButton, Toolbar } from "@/components/admin";
import { required, email } from "ra-core";
const CategoryToolbar = () => (
);
export const CategoryEdit = () => (
}
validate={(values) => {
const errors = {};
if (values.name && values.name.length < 3) {
errors.name = "Name must be at least 3 characters";
}
return errors;
}}
>
);
```
## TextInput Component
Text input field with label, validation, error display, and helper text.
```tsx
import { SimpleForm, TextInput } from "@/components/admin";
import { required, minLength, maxLength, regex } from "ra-core";
```
## SelectInput Component
Dropdown select with choices, supporting static lists and dynamic creation.
```tsx
import { SimpleForm, SelectInput, ReferenceInput } from "@/components/admin";
import { required } from "ra-core";
`${user.first_name} ${user.last_name}`}
emptyText="No author"
emptyValue={null}
/>
```
## AutocompleteInput Component
Searchable dropdown ideal for large datasets with remote filtering.
```tsx
import { SimpleForm, ReferenceInput, AutocompleteInput } from "@/components/admin";
import { required } from "ra-core";
`${customer.first_name} ${customer.last_name} (${customer.email})`}
inputText={(customer) => `${customer.first_name} ${customer.last_name}`}
filterToQuery={(searchText) => ({ q: searchText })}
validate={required()}
/>
}
onCreate={(tagName) => {
const newTag = { name: tagName };
return dataProvider.create('tags', { data: newTag })
.then(({ data }) => data);
}}
/>
```
## ReferenceInput Component
Input for selecting records from related resources (foreign key relationships).
```tsx
import { SimpleForm, ReferenceInput, AutocompleteInput, SelectInput } from "@/components/admin";
import { required } from "ra-core";
`${supplier.name} - ${supplier.city}`}
validate={required()}
/>
}
validate={required()}
/>
```
## ReferenceField Component
Displays fields from related records by following foreign key relationships.
```tsx
import { List, DataTable, ReferenceField, TextField, EmailField, ChipField } from "@/components/admin";
export const OrderList = () => (
(
{referenceRecord?.name}
{referenceRecord?.reference}
)}
/>
);
```
## TextField Component
Displays text values from record fields with optional formatting.
```tsx
import { Show, SimpleShowLayout, TextField } from "@/components/admin";
export const CustomerShow = () => (
(
{record.address}
{record.city}, {record.state} {record.zipcode}
)}
/>
);
```
## NumberField Component
Displays formatted numbers with currency, percentage, and locale support.
```tsx
import { List, DataTable, NumberField } from "@/components/admin";
export const ProductList = () => (
value / 10}
/>
);
```
## BulkActionsToolbar Component
Toolbar for performing bulk operations on selected records.
```tsx
import { List, DataTable, BulkActionsToolbar, BulkDeleteButton, BulkExportButton, BulkUpdateButton } from "@/components/admin";
import { useListContext, useUpdateMany, useNotify, useUnselectAll } from "ra-core";
const BulkSetFeaturedButton = () => {
const { selectedIds } = useListContext();
const notify = useNotify();
const unselectAll = useUnselectAll("products");
const [updateMany, { isPending }] = useUpdateMany(
"products",
{ ids: selectedIds, data: { featured: true } },
{
onSuccess: () => {
notify("Products updated successfully", { type: "success" });
unselectAll();
}
}
);
return (
);
};
export const ProductList = () => (
}
>
);
```
## Data Provider Implementation
Interface for connecting to any backend API (REST, GraphQL, custom).
```tsx
// Simple REST data provider
import simpleRestProvider from 'ra-data-simple-rest';
export const dataProvider = simpleRestProvider('https://api.example.com');
// Custom data provider
import { DataProvider } from 'ra-core';
export const customDataProvider: DataProvider = {
getList: async (resource, params) => {
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
sort: field,
order: order,
page: page,
per_page: perPage,
filter: JSON.stringify(params.filter),
};
const response = await fetch(
`https://api.example.com/${resource}?${new URLSearchParams(query)}`
);
const json = await response.json();
return {
data: json.items,
total: json.total,
};
},
getOne: async (resource, params) => {
const response = await fetch(`https://api.example.com/${resource}/${params.id}`);
const data = await response.json();
return { data };
},
create: async (resource, params) => {
const response = await fetch(`https://api.example.com/${resource}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(params.data),
});
const data = await response.json();
return { data };
},
update: async (resource, params) => {
const response = await fetch(`https://api.example.com/${resource}/${params.id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(params.data),
});
const data = await response.json();
return { data };
},
delete: async (resource, params) => {
await fetch(`https://api.example.com/${resource}/${params.id}`, {
method: 'DELETE',
});
return { data: params.previousData };
},
getMany: async (resource, params) => {
const query = { ids: params.ids.join(',') };
const response = await fetch(
`https://api.example.com/${resource}?${new URLSearchParams(query)}`
);
const data = await response.json();
return { data };
},
getManyReference: async (resource, params) => {
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
[params.target]: params.id,
sort: field,
order: order,
page: page,
per_page: perPage,
};
const response = await fetch(
`https://api.example.com/${resource}?${new URLSearchParams(query)}`
);
const json = await response.json();
return {
data: json.items,
total: json.total,
};
},
updateMany: async (resource, params) => {
const responses = await Promise.all(
params.ids.map(id =>
fetch(`https://api.example.com/${resource}/${id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(params.data),
})
)
);
return { data: params.ids };
},
deleteMany: async (resource, params) => {
await Promise.all(
params.ids.map(id =>
fetch(`https://api.example.com/${resource}/${id}`, {
method: 'DELETE',
})
)
);
return { data: params.ids };
},
};
```
## Auth Provider Implementation
Authentication interface supporting login, logout, permissions, and identity management.
```tsx
import { AuthProvider, HttpError } from "ra-core";
export const authProvider: AuthProvider = {
login: async ({ username, password }) => {
const response = await fetch('https://api.example.com/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
});
if (response.ok) {
const { token, user } = await response.json();
localStorage.setItem('token', token);
localStorage.setItem('user', JSON.stringify(user));
return Promise.resolve();
}
return Promise.reject(
new HttpError('Invalid credentials', 401, {
message: 'Invalid username or password'
})
);
},
logout: async () => {
localStorage.removeItem('token');
localStorage.removeItem('user');
return Promise.resolve();
},
checkAuth: async () => {
const token = localStorage.getItem('token');
if (!token) {
return Promise.reject();
}
// Verify token with backend
const response = await fetch('https://api.example.com/auth/verify', {
headers: { 'Authorization': `Bearer ${token}` }
});
return response.ok ? Promise.resolve() : Promise.reject();
},
checkError: async (error) => {
const status = error.status;
if (status === 401 || status === 403) {
localStorage.removeItem('token');
return Promise.reject();
}
return Promise.resolve();
},
getIdentity: async () => {
const userStr = localStorage.getItem('user');
if (!userStr) {
return Promise.reject();
}
const user = JSON.parse(userStr);
return Promise.resolve({
id: user.id,
fullName: `${user.first_name} ${user.last_name}`,
avatar: user.avatar_url,
});
},
getPermissions: async () => {
const userStr = localStorage.getItem('user');
if (!userStr) {
return Promise.reject();
}
const user = JSON.parse(userStr);
return Promise.resolve(user.role);
},
};
// Usage in App
import { Admin } from "@/components/admin";
import { authProvider } from "./authProvider";
{/* Resources */}
```
---
## Summary
Shadcn Admin Kit provides a complete solution for building production-ready admin interfaces with minimal configuration. The primary use cases include internal business tools, content management systems, e-commerce back-offices, data dashboards, and API administration panels. The library excels at rapid prototyping through its guesser components while remaining flexible enough for complex, customized implementations. It handles common admin requirements out-of-the-box: pagination, sorting, filtering, validation, authentication, authorization, optimistic updates, error handling, and bulk operations.
Integration patterns center around three core concepts: data providers for API connectivity (with 50+ pre-built adapters for popular backends), auth providers for security, and resource declarations that map UI components to API endpoints. The component architecture encourages composition, allowing developers to start with high-level components like `` and `` for standard views, then progressively customize with lower-level building blocks. All components integrate seamlessly with React Hook Form for validation, TanStack Query for data fetching, and React Router for navigation, while maintaining full type safety through TypeScript generics that flow from the data layer through to the UI.