Skip to content

dev-family/admiral

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

564 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Admiral logo

A React framework for building admin panels and back-office applications.
Provides CRUD generation, authentication, theming, routing, and 30+ UI components out of the box.

Live Demo  •  Blog & Use Cases  •  Migrating from v5

Version Downloads License


Features

  • CRUD generation — define a resource config, get index/create/update pages with tables, forms, filters, and pagination
  • 30+ UI components — Table, Form inputs, Select, DatePicker, Drawer, Tabs, Upload, Notification, and more
  • Conditional & dependent fieldsvisibleWhen / disabledWhen / requiredWhen rules on any input, Form.When groups, cascading selects
  • Validation-aware form tabsForm.Tabs shows per-tab error badges and switches to the first invalid tab on submit
  • File-based routing — pages directory maps to routes automatically (like Next.js)
  • Authentication — login, logout, OAuth (Google, GitHub, Jira), session checks
  • Theming — light/dark modes, fully customizable CSS presets
  • Localization — built-in i18n with swappable locale packs
  • TypeScript — full type coverage across all components and hooks

Tech Stack

React 19 • React Router 7 • Vite 6 • TypeScript 5.7 • @dnd-kit • @floating-ui • rc-* components • date-fns 4

Quick Start

Option 1 — scaffold a new project (recommended)

npx create-admiral-app@latest

You'll be prompted to choose:

  • With Express.js backend — fully configured template with an API server
  • Frontend only — just the admin panel, bring your own API

Then cd into the project, npm install, npm run dev — and you have a working admin panel.

Option 2 — add to an existing app

Requires Node.js >= 20 and a bundler (the examples below use Vite).

1. Install the package and its peer dependencies:

npm install @devfamily/admiral react@^19 react-dom@^19 react-router-dom@^7 axios@^1

2. Create the app entry. Import the styles once, wrap everything in <Admin>:

// src/App.tsx
import { Admin, createRoutesFrom } from '@devfamily/admiral'
import '@devfamily/admiral/style.css'
import Menu from './menu'
import dataProvider from './dataProvider'

// createRoutesFrom takes a map of page modules; with Vite use import.meta.glob
const Routes = createRoutesFrom(import.meta.glob('../pages/**/*', { eager: true }))

export default function App() {
    return (
        <Admin dataProvider={dataProvider('/api')} menu={Menu}>
            <Routes />
        </Admin>
    )
}

3. Add a menu:

// src/menu.tsx
import { Menu, MenuItemLink } from '@devfamily/admiral'

export default function AppMenu() {
    return (
        <Menu>
            <MenuItemLink icon="FiUsers" name="Users" to="/users" />
        </Menu>
    )
}

4. Add a data provider — the object that tells Admiral how to talk to your API. Copy src/dataProvider.ts as a starting point; the contract it implements is described in Data Provider below.

5. Create your first page — see the CRUD example. Done: /users now renders a table with forms, filters, and pagination.

Option 3 — run this repo

git clone https://github.com/dev-family/admiral.git
cd admiral
yarn
yarn dev

Open http://localhost:3000 — you'll see Admiral running on mock data, with the source for every page in pages/ and src/.

Core Concepts

Admiral apps are built from a handful of pieces: an <Admin> root, file-based routing, CRUD pages generated from a config, a data provider (and optionally an auth provider) that connect Admiral to your API, plus forms, filters, themes, and locales. Each piece is described below.

<Admin>

The root component. It wires up routing, theming, data fetching, auth, localization, and notifications — every other Admiral feature expects to live inside it.

<Admin
    dataProvider={dataProvider(apiUrl)} // required: how to fetch data
    menu={Menu} // required: sidebar menu component
    authProvider={authProvider(apiUrl)} // optional: enables the login flow
    themePresets={{ light, dark }} // optional: custom theme
    locale={admiralLocales.ruRU} // optional: translations
    logo={Logo} // optional: sidebar logo
    oauthProviders={[OAuthProvidersEnum.Google]} // optional: OAuth buttons
>
    <Routes />
</Admin>

Routing

Admiral uses file-system based routing. Files in the pages/ directory map to routes:

File Route
pages/index.tsx /
pages/users/index.tsx /users
pages/users/create.tsx /users/create
pages/users/[id].tsx /users/:id

CRUD Pages

Define a resource in one file — Admiral generates the index, create, and update pages:

// pages/users/index.tsx
import { createCRUD, TextInput, SelectInput } from '@devfamily/admiral'

export const { IndexPage, CreatePage, UpdatePage } = createCRUD({
    resource: 'users',
    path: '/users',
    index: {
        title: 'Users',
        newButtonText: 'Create User',
        tableColumns: [
            { title: 'ID', dataIndex: 'id', key: 'id' },
            { title: 'Name', dataIndex: 'name', key: 'name' },
            { title: 'Email', dataIndex: 'email', key: 'email' },
        ],
    },
    form: {
        create: {
            fields: (
                <>
                    <TextInput label="Name" name="name" required />
                    <TextInput label="Email" name="email" required />
                    <SelectInput label="Role" name="role_id" />
                </>
            ),
        },
        edit: {
            fields: (
                <>
                    <TextInput label="Name" name="name" required />
                    <TextInput label="Email" name="email" required />
                    <SelectInput label="Role" name="role_id" />
                </>
            ),
        },
    },
})

export default IndexPage

The full demo configs live in src/crud/.

Data Provider

The DataProvider interface defines how Admiral communicates with your API:

interface DataProvider {
    getList: (resource, params) => Promise<{ items: any[]; meta: PaginationMeta }>
    getOne: (resource, params) => Promise<{ data: any; values?: any }>
    create: (resource, params) => Promise<{ data: any }>
    update: (resource, params) => Promise<{ data: any }>
    deleteOne: (resource, params) => Promise<{ data: any }>
    getCreateFormData: (resource) => Promise<{ data?: any; values?: any }>
    getUpdateFormData: (resource, params) => Promise<{ data: any; values?: any }>
    getFiltersFormData: (resource, urlState?) => Promise<{ values?: any }>
    reorderList: (resource, params) => Promise<void>
}

See src/dataProvider.ts for a full implementation example.

API response format:

// GET /api/users?page=1&page_size=10
{
    "items": [{ "id": 1, "name": "John", "email": "john@example.com" }],
    "meta": { "current_page": 1, "last_page": 5, "per_page": 10, "total": 50 }
}

// Validation errors (HTTP 422)
{
    "errors": { "email": ["Email is required"] },
    "message": "Validation failed"
}

Auth Provider

Pass an authProvider to <Admin> and Admiral renders a login page, guards all routes, and keeps the session checked:

interface AuthProvider {
    login: (params: { username: string; password: string }) => Promise<any>
    logout: (params?: any) => Promise<void | false | string>
    checkAuth: (params?: any) => Promise<void>
    getIdentity: () => Promise<{ email: string; name: string }>
    oauthLogin?: (provider: OAuthProvidersEnum) => Promise<{ redirect: string }>
    oauthCallback?: (provider: OAuthProvidersEnum, data: string) => Promise<any>
}

See src/authProvider.ts for a full implementation example.

Forms & Inputs

CRUD forms are composed from ready-made inputs — each binds to a form value by name:

TextInput, MultilineTextInput, PasswordInput, SlugInput, SelectInput, AjaxSelectInput, RadioInput, BooleanInput, DatePickerInput, DateRangePickerInput, TimePickerInput, ColorPickerInput, EditorInput, FilePictureInput, DraggerInput, ArrayInput, TranslatableInput

Inside any form (or a custom input) the useForm() hook gives access to values, errors, and setters. Standalone forms outside CRUD are available via the Form component from @devfamily/admiral/form.

Conditional & dependent fields. Every input takes visibleWhen / disabledWhen / requiredWhen (a (values) => boolean or a JSON rule), <Form.When> reveals a group by one rule, and AjaxSelectInput supports resetOnChangeOf cascades (e.g. country → city). See Conditional & dependent fields.

Form.Tabs — validation-aware tabs. Long forms split into tabs that stay honest about errors: each tab shows a badge with its invalid-field count, and a failed submit switches to the first tab that needs attention (fields hidden by rules are skipped). See Form.Tabs.

Filters

Add a filter drawer to a CRUD index page with the filter key, and promote any of the fields to always-visible quick filters with quickFilters:

createCRUD({
    // ...
    filter: {
        topToolbarButtonText: 'Filter',
        fields: (
            <>
                <TextInput label="Name" name="name" />
                <BooleanInput label="Active" name="is_active" />
            </>
        ),
        quickFilters: ['name', 'is_active'],
    },
})

Applied filters are reflected in the URL, so filtered views are shareable and bookmarkable. A complete example: src/crud/quickFilters.tsx.

Theming

Light and dark modes work out of the box (with a switcher in the header). To customize colors, pass your own presets to <Admin>:

import themeLight from './theme/presets/themeLight'
import themeDark from './theme/presets/themeDark'
;<Admin themePresets={{ light: themeLight, dark: themeDark }}>
    <Routes />
</Admin>

Presets use @consta/uikit Theme under the hood. See admiral/theme/presets for the preset structure and CSS variables.

Localization

English is the default; a Russian pack ships in the box. Pass a ready-made pack to <Admin>, or a partial object — any top-level section you provide replaces the default one:

import { Admin, admiralLocales } from '@devfamily/admiral'
;<Admin locale={admiralLocales.ruRU}>
    <Routes />
</Admin>

Module Imports

Admiral supports granular imports to reduce bundle size:

import { Admin, createCRUD, createRoutesFrom } from '@devfamily/admiral'
import { Table, Button, Select, Drawer } from '@devfamily/admiral/ui'
import { Form, TextInput, SelectInput } from '@devfamily/admiral/form'
import { useTheme } from '@devfamily/admiral/theme'
import '@devfamily/admiral/style.css'

Hooks

Hook Description
useForm() Access form values, errors, options, and setters inside CRUD forms
useTheme() Get and set the active theme (light / dark)
useNav() Control sidebar collapse state and mobile burger menu
useGetIdentity() Get the authenticated user's identity
useLocaleProvider() Access the current locale configuration
useUrlState() Read/write state synced to the URL query string

Icons

Admiral uses React Icons (v5). Pass any icon name as a string or use JSX components directly.

Examples

Migrating from v5

v6 is a breaking release: React 19, React Router 7, ESM-only package, stricter types. The full checklist lives in MIGRATION.md. Migrating with an AI coding agent? Point it at MIGRATION_AI.md — the same guide as deterministic find → change → verify steps.

Using AI assistants

Two machine-oriented docs ship inside the npm package, so your agent can read them straight from node_modules/@devfamily/admiral/:

  • AI_GUIDE.md — an exact reference for generating Admiral code: the DataProvider contract and response shapes, where select/filter options come from, all 17 inputs, conditional-field rules, and the mistakes AI tools commonly make.
  • MIGRATION_AI.md — an executable v5 → v6 migration playbook.

The demo site also serves an index of these docs at admiral.dev.family/llms.txt.

Example prompt: "Read node_modules/@devfamily/admiral/AI_GUIDE.md, then add a CRUD page for the orders resource with a status filter and a conditional refund_reason field."

Contributing

Fork the repo, make your changes, and submit a pull request. We welcome contributions!

License

MIT © dev.family

Contact

Questions or feedback: admiral@dev.family

About

Admiral is a frontend framework for creating back office in React. It provides out-of-the-box components and tools that make developing an admin interface easy and fast.

Topics

Resources

License

Stars

249 stars

Watchers

7 watching

Forks

Contributors