Skip to content
AzuAzu

Fields

Fields become the create and edit forms, and the detail page. You list them on the resource, in the order you want them:

app/admin/resources/product_resource.ts
fields: [
field.text('name').section('Details'),
// inertia/admin/components/sku_input.tsx
field.text('sku').component('SkuInput').section('Details'),
field.decimal('price').section('Pricing').min(0),
field.belongsTo('category').section('Organisation').searchable('name'),
field.manyToMany('tags').section('Organisation').searchable('name'),
field
.select('status')
.section('Organisation')
.options({ draft: 'Draft', published: 'Published' }),
field.richText('description').section('Media'),
field.image('thumbnail').section('Media').maxSize('2mb'),
],
Field Form control Notes
text, textarea Input, auto-growing textarea
number Numeric input For numeric attributes (integers, floats). Supports min, max, step.
decimal Numeric input For decimal columns, which Postgres and MySQL return as strings. See Decimals.
boolean Toggle
select Dropdown, or radios for four or fewer options
date, datetime Date picker Uses the admin timezone. See Dates.
richText Rich text editor See Rich text.
file, image Drag-and-drop upload See Uploads.
belongsTo Searchable select Loads options as you type. See Relationships.
hasMany Table on the detail page See Relationships.
manyToMany Searchable picker that adds and removes related records See Relationships.

You won’t find required() on any field. Azu reads that from your VineJS validator, so the form and the rules can’t disagree. The same goes for limits like maxLength: the form shows what the validator enforces.

Use decimal for decimal columns. Postgres and MySQL return them as strings, and Azu keeps them that way.

  • The value stays an exact string end to end. It’s formatted with Intl.NumberFormat, never converted through Number.
  • It supports min, max, and step.
  • If the list column of the same name formats a currency, the input shows its code (NGN).

date and datetime fields use the admin timezone. That’s timezone in config/azu.ts, or else your server’s timezone. Admins enter and read dates in that timezone.

richText is sanitised on the server before your validator sees it, and again before it’s shown. So HTML written outside Azu (a seed, an API, a console) is safe to render too.

The editor is Tiptap, loaded only when a form needs it. Install its packages to use it:

Terminal window
npm i @tiptap/react @tiptap/pm @tiptap/starter-kit

Without them, the field is a plain HTML textarea.

Labels come from names. isFeatured reads “Is featured”. Common acronyms are capitals, so sku reads “SKU” and userId reads “User ID”. The same goes for URL, API, VAT, and UUID.

Give any field, column, filter, or action its own label with .label(). The demo’s stock column reads “In stock”:

app/admin/resources/product_resource.ts (columns)
// inertia/admin/components/stock_bar.tsx
column.custom('stock', 'StockBar').label('In stock'),
  • .section('Details') groups fields under a heading. See Forms.
  • .help('…') shows a hint under the control, and .placeholder('…') a placeholder in it.
  • .default(value) fills the create form.
  • .visibleOn('create') or .visibleOn('edit') shows the field on one form only.
  • .readOnly() shows the value without letting anyone change it.
  • .ability('publish') shows the field only to users the policy’s publish method allows. See Permissions.
  • .component('SkuInput') swaps in your own React component. See Customising.