Arc Rider Docs · Markdown

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.

En Ninox, el punto de entrada se llama arcCustomLayout({ ... }) en un campo de fórmula.

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:
WertBedeutung
"layout" (Default)Spinner sobre todo el layout
{ blockId: "sidebar" }Spinner solo sobre el bloque con este blockId indicator.type: dotsspinnerpulse — 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: &quot;auto&quot;, // Automatisch an den Inhalt angepasste Höhe. // default: height: &quot;300px&quot;, // 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: &quot;&quot;, // 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: &quot;recordId&quot;, &quot;type&quot;, &quot;field&quot;, &quot;value&quot; &quot;update&quot;

// Folgende Action benötigt 2 Parameter: &quot;type&quot;, &quot;value&quot; &quot;openUrl&quot;

// Folgende Action benötigt 2 Parameter: &quot;type&quot;, &quot;tableId&quot; &quot;openTable&quot;

// Folgende Actions benötigen nur den Parameter &quot;type&quot; &quot;closeFullScreen&quot; &quot;closeRecord&quot; &quot;closeAllRecords&quot;</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:
WertBedeutung
"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"
}

Modo pantalla completa (Ninox)

fullscreenMode oculta, con fullscreen: true, los elementos de formulario de Ninox. showAdminTools controla la llave de Ninox para otros administradores. hideHeaderIcons oculta los símbolos de Ninox en el header.

fullscreen: true,
fullscreenMode: "full",
showAdminTools: true,
hideHeaderIcons: true,