Back to Blog

Basic CRUD in Admiral

Contents
One of the core challenges in building admin panels is implementing a reliable and user-friendly data management system. In Admiral, CRUD (Create, Read, Update, Delete) is foundational functionality that enables the full lifecycle of working with table data – from creating new records to editing and deleting them.
When implemented well, CRUD operations empower users to interact with data more efficiently, thereby improving productivity and reducing the likelihood of errors during manual database interactions.
First, we’ll review the key components needed to implement a CRUD interface. Then, we'll walk through a practical example.
See an example of how the interface works at the demo stand:
https://admiral.dev.family/base-crud

Field Types

Admiral provides a wide range of field components for building CRUD interfaces. These components allow you to configure forms flexibly based on data types and business logic. Each field type is designed for a specific type of input, ranging from plain text and numeric values to selecting related entities and uploading files.
Here are some of the core field types:
  • TextInput – the text input field;
  • SelectInput – the field for selecting values, including multiple values;
  • FilePictureInput – the field for uploading files that also allows you to add multiple files;
  • BooleanInput – the logical field for displaying and changing a boolean value (true/false);
  • ArrayInput – a specialized field for displaying a collection of related items. For example, in an Order entity, it’s useful for rendering all associated line items (products).
Next we will consider each of the presented types of fields in detail, including its features, purpose, and examples of its use in the admin interface. This will help you better understand when to use a particular component for a specific task.

TextInput

Basic text input component, used for entering short string values. It is the most versatile field and is utilized in the majority of forms.

<TextInput label="Title" name="title" placeholder="Title" required columnSpan={2}/>
  • label – the displayed field title that tells the user what information to enter. It is usually placed above or next to the input field;
  • name – the unique field identifier used when submitting form data. The name also associates the field with the corresponding value in the data object;
  • placeholder – hint text displayed inside the field before values are entered. It helps users understand the expected format or example of the data being entered;
  • required – the Boolean value indicating that the field is required;
  • columnSpan – determines how many columns in the form grid this field occupies. Useful for alignment and customizing the visual layout of form elements.

SelectInput

Used to select a single value from a list. Commonly applied to select a status, category, type, or other predefined option. This method is especially useful when input should be restricted to a fixed set of choices.

<SelectInput label="By attribute" name="facet_id" placeholder="By attribute" required mode="multiple"columnSpan={2}/>
  • mode="multiple" – allows to select multiple values from the list. This is useful when you need to specify multiple categories, tags, or other parameters at the same time.

FilePictureInput

This field is used to upload images or files. It is typically used to add avatars, photos, and other visual materials.

<FilePictureInput columnSpan={2} label="Avatar" name="avatar" accept="image/*" maxCount={1} />
FilePictureInput properties:
  • accept – specifies the acceptable file types to upload. For example, "image/*" allows only images to be uploaded;
  • maxCount – limits the number of files that can be uploaded. A value of 1 means the user can upload only one file.

BooleanInput

This is a field for selecting a logical value (true or false). It is usually displayed as a checkbox or toggle and is used to control binary settings, such as "Active," "Published," "Display on Home," and other settings.

 <BooleanInput label="Active?" name="active" />
  • label – the displayable field title that prompts the user to enter information. It is usually placed above or next to the input field itself;
  • name – the unique field identifier used when submitting form data. It also associates the field with the corresponding value in the data object.

ArrayInput

This is a field intended for entering an array of similar objects. It allows users to add, edit, and delete multiple repeating blocks of data. This feature is particularly useful when it is necessary to specify a list of schedules, contacts, characteristics, and other structured sets.

 <ArrayInput label="Schedule" name="schedule" required>
            <SelectInput
              label="Day of the week"
              name="day"
              placeholder="Day of the week"
              required
             />
             <TimePickerInput
              label="Opening time"
              name="start_time"
              placeholder="Opening time"
              format="HH:mm"
             />
             <TimePickerInput
               label="Closing time"
               name="end_time"
               placeholder="Closing time"
               format="HH:mm"
             />          
  </ArrayInput>
  • required – the Boolean value indicating whether the field is required.
Additionally, nested fields such as SelectInput and BooleanInput can be used inside ArrayInput. Each nested field can also have its own properties and validations.

Example

Now that we are aware of the different types of fields, let's see how they work together within a single form. Below is an example of a typical CRUD form that uses different fields for text input, value selection, file uploads, and scheduling.
For example, this type of form can be used to create or edit an employee record in the admin area.
In the pre-prepared file, employer.tsx, we will define a constant with a set of fields.
const fields = (<>
<TextInput label="Name" name="name" placeholder="Enter a name" required />
<SelectInput label="Position" name="position"    placeholder="Choose a position" required />
<FilePictureInput label="Avatar" name="avatar" accept="image/*" maxCount={1} />
<BooleanInput label="Active" name="is_active" />
<AjaxSelectInput label="Department" name="department_id" placeholder="Choose a department" />
<ArrayInput label="Schedule" name="schedule">
  <TimePickerInput label="Start" name="start_time" placeholder="Start" format="HH:mm" />
  <TimePickerInput label="End" name="end_time" placeholder="End" format="HH:mm" />
  <BooleanInput label="Day off?" name="day_off" />
</ArrayInput>
<>)
Next, we’ll define the table structure and pass our fields into the create and edit properties. After that, the defined fields will appear in the create and edit forms within the interface.

export const CRUD = createCRUD({path: '/employers',
resource: resource,
index: {
title: 'Employers',
newButtonText: 'Add',
tableColumns: [
{
sorter: true,

title: 'ID',
dataIndex: 'id',
key: 'id',
width: 90,
},
       ],
},
form: {
create: {
   fields,
},
edit: {
    fields,
},
},
create: {
title: 'Addition'
},
update: {
title: (id: string) => `Editing`,
},
})

Backend

The request to retrieve data for a form will look like this:
https://admiral.dev.family/admin/emploers/489/update?id=489 

Table Management

To demonstrate how to manage the table, or the list of our database records, let's refer to the previous example. For clarity, I have only included the necessary block.

export const CRUD = createCRUD({path: '/employers',
resource: resource,
index: {
title: 'Employers',
newButtonText: 'Add',
tableColumns: [
{
sorter: true,

title: 'ID',
dataIndex: 'id',
key: 'id',
width: 90,
},
{
sorter: true,
title: 'Active',
dataIndex: 'is_active',
key: 'is_active',
render: (value) => (value ? 'Yes' : 'No'),
},

       ],
},
....
})
By the index.tableColumns key we can manage the table columns.
  • sorter – indicates that the data can be sorted by this column. Clicking on the header will sort the table by the corresponding value;
  • title – the column title displayed in the table header. It indicates which field is represented in this column (in this case, "Active");
  • dataIndex – the key from the data object by which the value in the cells will be displayed. It indicates which property from the data string to use (e.g., is_active);
  • key – unique identifier of the column that often coincides with dataIndex. It is used to optimize table performance, especially during updates;
  • render – function allows you to customize how the value in the cell will be displayed. In this example, "true" is rendered as "Yes" and "false" is rendered as "No."
  • width – allows to manually set the column size.

Form management

In order for the form data to load, you need to prepare it in this structure:

{
"data": {
"name": "Name",
"position": "Position",
"avatar": {
"uid": "uid", //unique file identifier
"name": "name.png",
"url": "https://admiral.dev.family/photo.png" //url to the image
},
"is_active": true,
"departmen_id": 1,
"schedule.start_time": "10:20",
"schedule.end_time": "11:20",
"schedule.day_off": true
},
"values": {
"departmen_id": [
{
"label": "Marketing",
"value": "7"
},
{
"label": "Accounting",
"value": "8"
}
]
}
}
Pay attention to the values, as they are necessary to load the SelectInput data for departments. In turn, the backend returns the department identifier – department_id.
The request to save or update the data will look like this:
https://admiral.dev.family/admin/emploers/489 (POST)
The query data is similar to the data needed to retrieve a form.

{
"name": "Name",
"position": "Position",
"avatar": {
"uid": "uid", 
"name": "name.png",
"url": "https://admiral.dev.family/photo.png" 
}, //will either be a binary file when uploading for the first time,or an object if the photo has already been uploaded.
"is_active": true,
"departmen_id": 1,
"schedule": [
{
"day_id": 1,
"start_time": "10:20",
"end_time": "11:20",
"day_off": true
},
{
"day_id": 2,
"start_time": "09:20",
"end_time": "12:20",
"day_off": true
}
]
}

Conclusion

Admiral provides a convenient and flexible way to implement CRUD interfaces for admin panels. Using components such as TextInput, SelectInput, FilePictureInput, BooleanInput, ArrayInput and others, you can quickly customize forms to create, view, edit and delete data.
Admiral allows you to:
  • Easily configure tables with sorting and custom data display;
  • Use out-of-the-box fields for various data types, including arrays and files;
  • Load and save data through an easy-to-understand API.
These features enable you to quickly deploy admin interfaces with minimal effort while maintaining high flexibility and scalability.
Still have questions about basic CRUD in Admiral? We’re here to help!

You may also like: