Referência

Tipos de campo

Os tipos de campo suportados e sua configuração.

Tipos de campo

Tipo Descrição
text Texto de uma linha
textarea Texto simples de várias linhas
html Texto formatado (editor bubble e barra do campo, veja Botões do editor)
slug Campo de slug seguro para URL, calculado a partir dos campos de origem configurados
boolean Chave verdadeiro/falso
date Seletor de data
email Endereço de e-mail
url URL
password Campo de senha criptografado
image Envio de uma imagem
file Envio de um arquivo
upload Envio genérico
gallery Envio de várias imagens
select Lista de opções, fixas ou de um recurso
number Entrada numérica, com min e max opcionais
color Seletor de cor
location-picker Mapa-múndi interativo que guarda a latitude no campo e a longitude no campo associado configurado em longitude_field

Os nomes dos tipos de campo precisam corresponder exatamente.

Configuração de campos

Opções comuns por campo:

Chave Tipo Descrição
name string Rótulo exibido no admin
required boolean Validação; defina em todos os campos de título e nome
admin_col boolean Mostrar na tabela da visão geral do admin (padrão: true)
admin_filter boolean ou objeto Acrescenta um filtro à visão geral do admin para um campo select ou boolean. Use { "default": <stored-value> } para ativá-lo com uma seleção padrão, e o "feature": "permission-name" opcional para mostrá-lo só a usuários com essa permissão. Independente de admin_col.
multi boolean Permitir vários valores
i18n boolean Traduzir por idioma
accept string Restrição de tipo de arquivo para campos image e file

Campos HTML devem usar explicitamente uma de duas configurações:

Simples (blocos curtos de texto, como uma introdução):

"buttons": "bold,italic",
"admin_col": false

Rica (conteúdo completo, como um corpo de texto):

"buttons": "h2,h3,h4,bold,italic,orderedlist,unorderedlist,quote,anchor",
"media": true,
"media_sizes": "sm-90,md-70,lg-60,xl-50,xxl-40",
"admin_col": false

Nunca defina um campo html sem escolher uma delas. media_sizes é obrigatório quando media: true.

Botões do editor. buttons lista os botões de formatação de um campo html, em ordem. Sem buttons, um campo recebe bold,italic,removeFormat. Integrados:

Botão Faz
bold, italic Formatação no texto (Ctrl/Cmd+B, Ctrl/Cmd+I)
h2, h3, h4, quote, pre Formato de bloco; repetir volta a ser parágrafo
orderedlist, unorderedlist Listas
anchor Link: adicionar, editar (pré-preenchido) ou remover; Ctrl/Cmd+K
removeFormat Limpar formatação
strikethrough, subscript, superscript, underline Opcionais, em nenhum conjunto padrão

Os mesmos botões aparecem em dois lugares: a barra bubble no texto selecionado e a barra do campo. Nos formulários do admin a barra do campo faz parte da caixa do campo; na edição na página ela flutua acima do campo em foco e também tem Media (quando media: true) e Save (Ctrl/Cmd+S). Alt+F10 leva o foco do teclado à barra do campo. Colar mantém só texto simples, a menos que o campo defina "paste_html": true, que mantém a formatação básica e remove o markup do Word e do Google Docs.

Botões próprios do editor. Um projeto declara seus próprios botões como JSON em ext/tpl/bubble-editor-buttons/index.tpl (o template pode usar shortcodes, como [#text ...#] para rótulos) e os lista no buttons de um campo como os integrados:

{
    "highlight": { "kind": "wrap", "tag": "mark", "label": "[#text Highlight#]", "icon": "M" },
    "h5": { "kind": "block", "tag": "h5", "label": "Heading 5", "icon": "H5" },
    "poi": {
        "kind": "event", "event": "nb:insert-point", "insert": true, "bubble": true,
        "active": "[data-poi-link]", "label": "[#text Point of interest#]", "icon": "<svg ...></svg>"
    }
}
Tipo Faz
command Um comando de formatação ("command": "bold")
block Formato de bloco ("tag": "h5")
list Comando de lista
wrap Envolve a seleção num elemento ("tag", "class" opcional); repetir desfaz
insert Insere um HTML fixo no cursor ("html")
event Dispara um evento DOM no campo ("event", com bubbling, detail: { editor, range }) para o código próprio do projeto, por exemplo para abrir um seletor
link Pede uma URL, como anchor

Opções: "insert": true coloca um botão ao lado de Media na barra do campo em vez de junto dos botões de formatação; acrescente "bubble": true quando ele também age sobre texto selecionado; "active" é um seletor que marca o botão como ativo quando o cursor está dentro de uma correspondência. Links são a[href]: um projeto pode usar <a> sem href para elementos próprios no texto. O código também pode registrar botões com nb.bubble_editor.register(name, { label, icon, run(ctx), is_active(ctx) }).

As ferramentas de edição de um projeto (o modal e o script por trás de um botão event) ficam em ext/tpl/edit-extras/index.tpl, exibido para usuários que podem editar na página, em páginas do site e do admin.

Campos de slug:

Slugs são campos explícitos. Não acrescente "slug": true a outro campo. Defina um campo separado com "type": "slug" e um source que aponte para o campo ou os campos de que ele é derivado.

O formulário do admin calcula o slug no navegador a partir dos campos de origem, antes do envio. A API não inventa campos de slug que faltam ao salvar; ela guarda o valor do campo de slug que recebe. Se um código cria ou importa registros fora do formulário do admin, ele também precisa definir o valor do campo de slug.

Defina "preserve_existing": true no campo de slug para gerar slugs que faltam, mantendo inalteradas as URLs já salvas quando o formulário abre ou quando o título de origem muda. Os editores ainda podem mudar um slug salvo de propósito.

"url_slug": {
  "name": "URL slug",
  "type": "slug",
  "source": "title",
  "admin_col": false
}

Várias origens são separadas por vírgula; os valores são unidos com um espaço antes de virar slug:

"url_slug": {
  "name": "URL slug",
  "type": "slug",
  "source": "title,date",
  "admin_col": false
}

Com "source": "title,date", título "Jazz Night" e data "2026-04-09", o slug vira jazz-night-2026-04-09. Acrescente sempre url_slug à lista index do recurso, para que ele possa ser buscado no route.inc.

Se o campo de origem é i18n, o campo de slug também é tratado como i18n. Por exemplo, title.nl, title.en e title.fr geram valores correspondentes em title_slug.nl, title_slug.en e title_slug.fr. Não traduza slugs à mão; deixe o campo de slug derivá-los dos valores de origem de cada idioma.

Campos de seleção:

Opções fixas:

"type": "select",
"options": {
  "new": "New",
  "active": "Active",
  "closed": "Closed"
}

Opções de outro recurso:

"type": "select",
"resource": "categories"

Os filtros da visão geral do admin são ativados por campo, em campos select e boolean:

"status": {
  "type": "select",
  "options": { "active": "Active", "closed": "Closed" },
  "admin_filter": { "default": "active" }
},
"published": {
  "type": "boolean",
  "admin_col": false,
  "admin_filter": true
}

Os filtros comparam os valores brutos guardados, enquanto exibem as opções configuradas ou os rótulos do recurso relacionado. Seleções com vários valores correspondem quando o registro contém o valor escolhido. Vários filtros se combinam com E e continuam funcionando com busca, ordenação e paginação. As seleções ficam na URL como filter[field]=value. Um parâmetro ausente usa o padrão configurado; um parâmetro vazio escolhe explicitamente All. Valores inválidos na URL viram All.

Campos de localização:

Use location-picker quando os editores devem escolher coordenadas num mapa em vez de digitá-las. O campo seletor guarda a latitude no próprio campo e atualiza um campo numérico separado de longitude, indicado em longitude_field. Oculte o campo associado com wrapper_class: "hidden", para que o editor veja um único controle enquanto o recurso guarda coordenadas simples:

"location_lat": {
  "name": "Location",
  "type": "location-picker",
  "longitude_field": "location_lng",
  "required": true,
  "admin_col": false
},
"location_lng": {
  "name": "Longitude",
  "type": "number",
  "required": true,
  "min": -180,
  "max": 180,
  "wrapper_class": "hidden",
  "admin_col": false
}

Como os campos de formulário são gerados

Esta seção mostra o caminho completo, da definição de um campo num recurso até o campo exibido no formulário. Leia antes de criar um novo tipo de campo.

Visão geral

.meta field definition
  ↓
render_field() - PHP (core/modules/forms/lib/render-field.php)
  ↓
_f.* template variables
  ↓
[#field-{type}#] template (core/modules/forms/tpl/field-{type}/index.tpl)
  ↓
Alpine.js form_data.{field}   ← x-model binding
  ↓
API POST/PUT on submit

render_field() e o contexto _f.*

render_field() é a porta de entrada. Ele:

  1. Recebe um array com a definição do campo, a chave do campo e parâmetros opcionais de valor, armazenamento e origem
  2. Espalha a definição inteira do campo em _f.* via set_variable_dot('_f', $def); todo atributo do .meta fica disponível automaticamente no template
  3. Define variáveis calculadas por cima: _f.key, _f.title, _f.value, _f.model, _f.required, _f.ai, _f.bg
  4. Passa para [#field-{type}#], o template desse tipo de campo

_f.model é a expressão do Alpine.js para x-model, calculada como {store}.{field}. O armazenamento padrão é form_data. Em campos i18n ela vira form_data.{field}[{lang}].

Variáveis _f.* padrão disponíveis em todo template de campo:

Variável Conteúdo
_f.key Nome do campo / atributo name do HTML
_f.title Rótulo (de name no .meta)
_f.value Valor pré-preenchido
_f.model Expressão x-model do Alpine, por exemplo form_data.email
_f.required Se o campo é obrigatório
_f.bg Classe da cor de fundo do rótulo flutuante
_f.* (qualquer) Todas as outras chaves da definição do campo: _f.accept, _f.options, _f.resource etc.

form_data: o store do Alpine.js

form_data é o objeto reativo do Alpine.js que guarda todos os valores atuais dos campos. Ele é declarado no elemento <form>. Cada campo grava seu valor ali via x-model="[#_f.model#]".

No envio, form_data é colocado no payload da API e enviado por POST para /api/v1/{resource}. Campos com editor rico (HTML, gallery, image) gravam seus valores por um mecanismo separado (nb.edit.get_field_values()), que é combinado automaticamente; os templates de campo não precisam cuidar disso.

O template de campo mais simples

field-default/index.tpl é a base dos campos de texto:

<div class="[#_f.wrapper_class#]">
    <input type="[#_f.type#]" value="[#_f.value#]" name="[#_f.key#]"
        x-init="[#_f.model#]=`[#_f.value#]`"
        x-model="[#_f.model#]"
        [#if _f.required=(not-empty) echo=required#]
        class="input input-bordered w-full" />
    <label class="pointer-events-none absolute left-3 -top-2.5 px-1
            font-bold text-sm leading-tight [#get _f.bg default=bg-neutral-50#]">
        [#_f.title#][#if _f.required=(not-empty) echo=" *"#]
    </label>
</div>

Acrescentando um novo tipo de campo

  1. Crie o template:

    core/modules/forms/tpl/field-{type}/index.tpl   ← core types
    ext/tpl/field-{type}/index.tpl                   ← project-specific types
    
  2. No template:

    • Ligue ao Alpine via x-model="[#_f.model#]"
    • Defina o valor inicial com x-init="[#_f.model#]='[#_f.value#]'"
    • Use [#_f.key#] como atributo name do HTML
    • Acesse opções específicas do tipo via _f.* (por exemplo [#_f.accept#] para restrições de arquivo)
  3. Use o nome do tipo no .meta; ele funciona assim que o template existe.

  4. Se o campo gerencia um estado complexo (como um seletor de arquivo ou um botão do navegador de mídia), aninhe um x-data próprio dentro do x-data do formulário. O form_data externo continua acessível a partir dos escopos aninhados.

Campos próprios usam a convenção de template field-{type} e o contexto _f.* (_f.model, _f.key, _f.title, _f.bg etc.). Templates de campo de uma geração anterior, com _fmodel, _fid, _ftitle, _fbg, _bf_render_field() ou atributos data-te-* do Tailwind Elements, são refeitos nessa forma em vez de mantidos.

Campos aninhados e repetidores precisam gerenciar explicitamente os caminhos de modelo aninhados do Alpine. Por exemplo, um campo group que guarda locations deve ligar os campos filhos a caminhos como form_data.locations[ix].location, ou passar um modelo explícito ao reutilizar render_field(). Não suponha que o renderizador do core consiga deduzir caminhos de arrays aninhados a partir de uma chave de campo plana.

Ver esta página em Markdown