Premium Widgets
Custom Layout
Custom Layout
AI Defaults
- Dashboard wrappers
- MUST have `fullscreen: true`, `fullscreenMode: if isAdminMode() then "" else "full" end`, `height: "100%"`.
- embedded
- `false` for standalone/dashboard layouts, `true` when nested inside another widget.
- direction
- Always set explicitly (`"horizontal"` or `"vertical"`).
- Block widths
- At least one block should use `width: "fraction"` to fill remaining space.
- Scrollable areas
- Use `height: "fraction"` + `scrollSettings: { scrollY: true }` for content below fixed headers.
- uniqueId
- Required, no special characters.
- Sticky headers
- Need `overflow-x: hidden` on parent (NOT `overflow: hidden`), background-color, and z-index.
- Two for-loops
- NEVER place two for-loops side by side in blocks – each needs its own wrapper layout.
- Nested widgets (Next-Gen)
- In `blocks[].value`, use `{ widget: "arc-widget-…", uid: "…", data: { … } }` — not `arcCustomXxx({ … })`. Requires current `bundle.js`; legacy Ninox-formula widgets do not support this. See `docs/patterns/nested-widget-descriptors.md`.
Custom Layout
Con el widget Layout diseñas interfaces sin rejilla de tabla — un contenedor flexible (como Flexbox): alineación, espaciado, colores, widgets anidados.
Ya sea que quieras colocar secciones sencillas una junto a otra, construir una tarjeta informativa con fondo gráfico o estructurar elementos interactivos en una página — arcCustomLayout es tu herramienta para ello.
Con esto controlas:
- Orientación (horizontal / vertical)
- Espaciado, colores, imágenes de fondo
- Comportamiento flexible según tamaño de pantalla
- Estilos individuales por bloque
- Interacciones (p. ej. acciones de clic en áreas)
A diferencia de arcCustomGrid, pensado para estructuras bidimensionales (filas *y* columnas), el Layout trabaja deliberadamente de forma unidimensional: determinas si los contenidos se muestran horizontalmente (uno junto a otro) o verticalmente (uno debajo de otro) — incluyendo alineación, espaciado, colores y adaptaciones responsivas.
🎯 Lo que puedes hacer con esto:
- Layouts tipo tarjeta con título, descripción y botones uno junto a otro
- Áreas hero con un gran bloque de texto + imagen uno junto a otro (horizontal)
- Bloques de formulario verticales con espaciado específico y color de fondo
- Bloques interactivos con funciones de clic (popup, update, eliminar, etc.)
- Combinación de varias fuentes de datos en un layout dinámico
Código de aplicación
Inicio rápido – Layout base simple
Un ejemplo compacto con el que puedes empezar directamente. Ideal cuando quieres colocar algunos contenidos uno junto a otro (direction: "horizontal") o uno debajo de otro (direction: "vertical") — por ejemplo bloques de texto, KPIs o botones. Los parámetros más importantes, como alineación, ancho y espaciado, ya están definidos y se pueden adaptar fácilmente.
✅ Uso rápido ✅ Flexible y adaptable ✅ Perfecto para copiar y empezar
arcCustomLayout({
uniqueId: "Beispiel "+ Nr,
embedded: true,
direction: "horizontal",
alignX: "left",
alignY: "center",
width: "100%",
height: "auto",
gap: "10px",
backgroundColor: "",
paddingY: "",
paddingX: "",
styles: "",
scrollSettings: {
scrollY: false,
scrollX: false,
},
blocks: [{
width: "fraction",
height: "auto",
lineHeight: "",
alignX: "left",
color: "",
styles: "",
value: ""
}, {
width: "auto",
height: "auto",
lineHeight: "",
alignX: "left",
color: "",
value: "",
}] })</code></pre>
Layout completo – Layout ancho en el contenedor de un registro
Este setup está pensado para layouts que no están integrados y se extienden por toda el área de contenido de un registro o de una página. Especialmente adecuado para dashboards, páginas de resumen o pantallas de inicio que deban resultar ordenadas y enfocadas dentro de Ninox.
✅ Ancho completo dentro de la pestaña o del registro ✅ Sin integrar — el layout se sostiene por sí mismo ✅ Ideal para componentes más grandes, paneles o páginas de resumen
Código con todos los parámetros
arcCustomLayout({
uniqueId: Nr,
embedded: true,
fullscreen: false, // Gibst du hier "true" an, wird das Layout in dem ganzen Datensatz eingebunden
fullscreenMode: "full",
page: false, // Gibst du an, wenn du den fullscreen auf einer Tabelle einstellen möchtest.
showAdminTools: false,
hideHeaderIcons: true,
direction: "vertical",
alignX: "center",
alignY: "center",
width: "",
height: "",
gap: "5px",
backgroundColor: "#ccc",
paddingY: "10px",
paddingX: "5px",
blocks: [{
width: "",
height: "auto",
lineHeight: "1.6",
alignX: "left",
value: "",
color: "#000",
styles: "", // Hier kannst du eigene CSS Styles hinterlegen.
clickAction: {
recordId: Nr,
type: "popup"
}
}, {
width: "",
height: "auto",
lineHeight: "",
alignX: "left",
value: "",
color: "", // Fallback: "#000"
clickAction: {
type: "openFullscreen",
recordId: raw(record(Firmen,1).Nr)
},
}]
})
💡Nota: También puedes anidar varios layouts entre sí. Así puedes construir interfaces complejas y hacer que Ninox resulte aún más claro.
Ajustes generales
Los parámetros de arriba indican los ajustes generales de todo tu layout. Es, por así decirlo, el contenedor más externo de tu layout.
uniqueId
uniqueId es la denominación individual de tu layout. Asegúrate de asignar aquí un título único. Esto es importante si quieres mostrar varios layouts en una página / en una tabla y que no se sobrescriban entre sí.
uniqueId: "Layout container",
embedded
embedded indica si tu layout debe integrarse en otro widget.
embedded: true, // Ja, es wird in einem anderen Widget integriert
embedded: false, // Nein, es ist nicht in anderen Widgets integriert
embedded: false, // default: false
fullscreen
fullscreen determina si tu layout debe mostrarse en toda la pantalla (registro / página).
fullscreen: true,
fullscreen: false, // default: false
ninoxVersion
ninoxVersion indica la versión de Ninox Web en la que te encuentras (p. ej. "3.13"). Para un comportamiento de pantalla completa correcto, establécelo; los valores a partir de 3.13 también aplican a versiones más nuevas (p. ej. 3.15).
ninoxVersion: "3.13",
page
page define si integras el layout en una página o en una tabla. true = página, false = tabla / registro. Antes fullscreenMode: "full" solo actuaba en páginas; con page: false la pantalla completa también actúa sobre registros de una tabla.
page: true, // Page
page: false, // Tabelle / Record
fullscreenMode
fullscreenMode: "full" oculta el header y las pestañas de Ninox. Úsalo junto con fullscreen: true y ninoxVersion.
fullscreenMode: "full",
fullscreenMode: "", // default: kein Full-Chrome-Hide
showAdminTools
showAdminTools controla si el botón de admin (llave de Ninox) permanece visible para los administradores.
showAdminTools: true,
showAdminTools: false, // default: false in vielen Dashboard-Beispielen
scrollSettings
scrollSettings controla si el layout tiene scroll vertical (scrollY) u horizontal (scrollX). El layout recuerda la posición de scroll — tras triggers que recargan Ninox brevemente, se conserva la última posición.
scrollY
scrollSettings: {
scrollY: true,
scrollX: false,
}
scrollX
scrollSettings: {
scrollY: false,
scrollX: true,
}
direction
direction indica cómo se deben organizar tus demás contenidos (blocks).
direction: "vertical", // Alle Inhalte werden untereinander angeordnet.
direction: "horizontal", // Alle Inhalte werden nebeneinander angeordnet.
### alignX
alignX: indica cómo se organizan tus contenidos en el eje X.
alignX: "center", // zentriert // default: center
alignX: "left", // linksbündig
alignX: "right", // rechtsbündig
alignX: "between", // teilt Blocks auf Gesamtbreite auf
alignY
alignY: indica cómo se organizan tus contenidos en el eje Y.
alignY: "center", // zentriert // default: center
alignY: "top", // oben angeordnet
alignY: "bottom", // unten angeordnet
alignY: "between", // teilt Blocks auf Gesamthöhe auf
### width
width indica el ancho.
width: "100%", // Prozent-Werte. Hier: volle Breite.
width: "100px", // Pixel-Werte
height
height indica la altura.
height: "auto", // Automatisch an den Inhalt angepasste Höhe.
height: "300px", // Pixel-Werte
gap
Con gap determinas cuánto espacio debe haber entre tus blocks.
gap: "5px", // Pixel-Werte
actions (clic en todo el layout)
Con actions a nivel de widget (no dentro de un bloque) haces que todo el layout sea clicable — útil, por ejemplo, para un wrapper de tarjeta o un dimmer móvil, sin necesidad de un bloque propio para ello.
actions: [{
recordId: Nr,
type: "popup"
}]
Varias entradas se ejecutan de forma consecutiva, dataBag funciona igual que en cualquier otra action de tipo update/create:
actions: [{
type: "update",
recordId: Nr,
fieldId: fieldId(Nr, "helper_mainContentState"),
dataBag: {
base: helper_mainContentState,
patch: { sidebarOpen: "" }
}
}]
Importante: Si un bloque individual tiene sus propias actions o clickAction, su clic no se propaga adicionalmente a las actions del widget (sin doble disparo) — solo los clics fuera de un bloque configurado activan las actions del widget.
Detalles sobre las actions de bloque: <a href="#actions-block-empfohlen"><code>actions Block</code></a> más abajo.
loading (nivel de widget)
Con loading controlas si aparece un spinner sobre el área de destino al ejecutar las actions del widget. Sin loading (o con show: false) la action se ejecuta como hasta ahora — solo sin feedback visual.
loading: {
show: true,
target: "layout", // Default: "layout" | { blockId: "sidebar" }
indicator: { type: "spinner", color: "#4970ff", width: "32px", height: "32px" },
dim: true, // halbtransparenter Hintergrund über dem Zielbereich
minDuration: 300, // Mindest-Anzeigedauer in ms
hideOnFinish: true // Default: true
}
** `target` **a nivel de widget:
Wert Bedeutung "layout" (Default)Spinner sobre todo el layout { blockId: "sidebar" }Spinner solo sobre el bloque con este blockId indicator.type: dots spinnerpulse — igual que en el botón.
overlay (modal a pantalla completa)
Con loading.overlay aparece, en lugar del overlay local de bloque/layout, un modal a pantalla completa sobre toda la vista — idéntico al del botón (arcModalWindows). target y dim se ignoran en este modo.
overlayVerhalten trueSolo backdrop + spinner { title, message }Mensaje fijo en la tarjeta del diálogo { sequences: [...] }Mensajes dinámicos (tiempo y/o booleanos de Ninox)
loading: {
show: true,
overlay: {
title: { value: "Wird gespeichert…", styles: "font-size: 18px; font-weight: 700;" },
message: "Bitte einen Moment warten.",
indicator: { type: "spinner", color: "#4970ff", width: "32px", height: "32px" }
},
minDuration: 300,
hideOnFinish: true
}
API completa de overlay (width, height, backgroundColor, sequences, when, priority): consulta <a href="../mini_widgets/buttons.md#overlay-zusätzlich">Button Loading — overlay</a>.
Ajustes en el bloque de layout
Los parámetros dentro de un bloque determinan los valores correspondientes a cada bloque de layout. También puedes añadir más bloques (separados por comas).
blocks: [{ // Beginn Block 1
blockId: "sidebar", // optional — stabile ID für Loading-Targeting
width: "",
height: "auto",
lineHeight: "1.6", // default: normal
alignX: "left",
color: "#000", // Schriftfarbe von Text im Layoutblock
backgroundColor: "#333", // Hintergrundfarbe von Text im Layoutblock
styles: "", // Hier kannst du eigene CSS Styles hinterlegen.
value: "", // Hier gibst du den Wert an, der im Block ausgegeben werden soll.
clickAction: {
recordId: Nr,
type: "popup"
}
},
{ // Beginn Block 2
width: "",
height: "auto",
lineHeight: "1.6", // default: normal
alignX: "left",
color: "#000",
backgroundColor: "#ccc",
styles: "", // Hier kannst du eigene CSS Styles hinterlegen.
value: "",
clickAction: {
recordId: Nr,
type: "popup"
}
}
}]
width
width y height indican el ancho y la altura del bloque de layout.
width: "auto", // Automatisch an den Inhalt angepasste Weite. // default:
width: "300px", // Pixel-Werte oder Prozenz-Werte
height: "auto", // Automatisch an den Inhalt angepasste Höhe. // default: height: "300px", // Pixel-Werte oder Prozenz-Werte</code></pre>
lineHeight
Con lineHeight determinas el espacio entre líneas en el layout.
lineHeight: "1.6", // default: normal
alignX
alignX: indica cómo se organizan tus contenidos en el eje X dentro del bloque de layout.
alignX: "center", // zentriert // default: center
alignX: "left", // linksbündig
alignX: "right", // rechtsbündig
alignX: "between", // teilt Blocks auf Gesamtbreite auf
color & backgroundColor
Con color y backgroundColor determinas el color del texto y el color de fondo del texto dentro de tu bloque de layout.
color: "#33AAFF", // default: #000
backgroundColor: "#ccc", // default: no default color
styles
En styles puedes añadir tus propios estilos CSS al bloque de layout.
styles: "", // z.B. font-weight: 700;
value
value es el valor que se representa dentro del bloque de layout. Aquí puedes indicar, por ejemplo, texto, campos de Ninox o customWidgets.
value: "Überschrift", // einfacher Text
value: Titel, // Ninox-Feld
value: arcCustomButton({...}) // Top-Level oder Legacy: Funktionsaufruf
value: "", // default: Gibst du keinen Wert an, wird nichts ausgegeben ;)</code></pre>
Widgets anidados (Next-Gen, notación de objeto)
Cuando un bloque contiene otro arcWidget y ambos provienen del bundle.js actual, puedes establecer un objeto descriptor en lugar de arcCustomButton({ … }):
value: {
widget: "arc-widget-button",
uniqueId: "block-btn-" + Nr, // uid: "block-btn-" + Nr ist gleichwertig
data: {
title: "Speichern",
actions: [{ type: "update", recordId: Nr, field: fieldId(Nr, "Status"), value: "done" }]
}
}
- widget: ID interna (arc-widget-layout, arc-widget-button, …) — no el nombre de la función - uniqueId o uid: ambos aceptados — top-level, no dentro de data - data: los mismos parámetros que en la llamada de función
Importante: Solo funciona con widgets Next-Gen en el bundle. Las fórmulas legacy de Ninox antiguas (todavía no desplegadas como widget JS) no entienden estos objetos.
En detalle: <a href="../patterns/nested-widget-descriptors.md"><code>nested-widget-descriptors</code></a>
Bloque actions (recomendado)
actions describe tus acciones en los bloques respectivos como array. Varias entradas se ejecutan de forma consecutiva — p. ej., primero vaciar el estado, luego abrir el registro.
actions: [{
recordId: Nr,
type: "update",
fieldId: fieldId(Nr, "helper_uiState"),
dataBag: {
base: helper_uiState,
patch: { activeTab: "details" }
}
}, {
recordId: Nr,
type: "popup"
}]
openTable abre una vista de tabla en Ninox:
actions: [{
type: "openTable",
tableId: "A"
}]
openUrl abre una URL externa:
actions: [{
type: "openUrl",
value: "https://www.arc-rider.com"
}]
Tipos de action (igual que en Button y otros widgets):
Trigger update repetido con polling + booleano de fórmula active: consulta <a href="../patterns/action-polling.md"><code>action-polling</code></a>.
// Folgende Actions benötigen die zwei Parameter: "recordId" und "type"
"popup"
"delete"
"openRecord"
"fullscreen"
// Folgende Action benötigt die 4 Parameter: "recordId", "type", "field", "value" "update"
// Folgende Action benötigt 2 Parameter: "type", "value" "openUrl"
// Folgende Action benötigt 2 Parameter: "type", "tableId" "openTable"
// Folgende Actions benötigen nur den Parameter "type" "closeFullScreen" "closeRecord" "closeAllRecords"</code></pre>
Actualizaciones parciales de estado mediante dataBag en actions de tipo update: <a href="../patterns/data-bag-actions.md"><code>data-bag-actions</code></a>.
Bloque loading
Con loading a nivel de bloque controlas el spinner al ejecutar las actions del bloque. El destino puede ser el propio bloque, otro bloque o todo el layout.
blockId: "save-panel",
actions: [{ type: "update", recordId: Nr, field: fieldId(Nr, "Status"), value: "done" }],
loading: {
show: true,
target: "block", // Default: "block" | "layout" | { blockId: "other" }
indicator: { type: "spinner", color: "#4970ff" },
dim: true,
minDuration: 300,
hideOnFinish: true
}
** `target` **a nivel de bloque:
Wert Bedeutung "block" (Default)Spinner sobre el bloque pulsado "layout"Spinner sobre todo el layout { blockId: "sidebar" }Spinner sobre otro bloque (mediante blockId) blockId es opcional, pero necesario si quieres dirigirte a otro destino mediante { blockId: "…" }. El ID debe ser único en la página — { blockId: "…" } busca primero en el mismo layout, y luego en toda la página (así que también funciona si el bloque de destino está en un layout superior que anida este layout mediante blocks[].value: { widget: "arc-widget-layout", … }).** loading.overlay también funciona a nivel de bloque — entonces aparece el modal a pantalla completa en lugar del overlay local (consulta <a href="#overlay-fullscreen-modal">overlay (nivel de widget)</a> más arriba).
Mientras una action está en ejecución, los clics repetidos en la misma área de destino quedan bloqueados (protección de reentrada).
Bloque clickAction (Legacy)
El antiguo campo individual clickAction sigue siendo compatible y se ejecuta como una entrada en actions. Para configuraciones nuevas usa actions**.
clickAction: {
recordId: Nr,
type: "update",
field: "",
value: ""
}
clickAction: {
type: "openTable",
tableId: "A"
}
clickAction: {
type: "openUrl",
value: "https://www.arc-rider.com"
}
Vue
El objeto data se pasa como prop al componente Vue.
<ArcWidgetLayout id="shell" :data="layoutData" @action="handleAction" />