---
title: "Custom Kanban"
slug: "custom-kanban"
category: "Widgets"
reactComponent: "ArcWidgetKanban"
reactTier: "premium"
reactSince: "0.1.0-alpha.5"
reactExample: "kanban.tsx"
locale: "es"
hosts: "ninox"
---

# Custom Kanban


# Custom Kanban

## AI Defaults (read first)

- **uniqueId**: Required, `"kanban-" + Nr`.
- **height**: Use `"100%"` when embedded in a dashboard layout.
- **Swimlane minWidth**: Set `minWidth: "300px"` for readable swimlanes.
- **recordId**: Use raw `Nr` in swimlanes, NEVER `number(Nr)`. Stays on the formula; core never reads it. Drop handler looks up `ui.data.swimlanes[target_swimlane_index].recordId`.
- **fieldId**: Use `fieldId(Nr, "Feldname")`, NOT the display name as string. Drop persistence is Ninox-handler only — core does not read `fieldId`.
- **items mapping**: Use `.[{ itemId: Nr, ... }]` with `Nr` (not `number(Nr)`). `itemId` stays on the formula. Core emits swimlane/section/item **indices**; the handler reads `itemId` / `fieldId` from `ui.data.swimlanes[i]`.
- **sections** (optional pro Swimlane): `[{ id: "…", title: "…", items: [ … ], hideWhenEmpty: false, collapsed: false }]`. Ohne `sections` oder leer → flaches `items` wie bisher (eine implizite Gruppe, kein Gruppenkopf). `id` ist Pflicht sobald Gruppen genutzt werden (State).
- **scrollSettings**: Root: `scrollX` / `scrollY` mit `scrollbar: { enabled: boolean }` fuer das gesamte Kanban (ersetzt/ergaenzt `showScrollbar` fuer X). Pro Swimlane: `scrollY.scrollbar.enabled` fuer vertikales Scrollen in der Spalte.
- **dragAction**: Needs `fieldId` (field ID) for the status field being updated on drag. Adapter-only.
- **Persistence**: Card drag saves in the **Ninox handler** (`type: "update"` from `item.fieldId` + target swimlane `recordId`). React hosts: `onItemDrop` / `onAction('item_drop')` — **no** global `database` stub.
- **clickable**: Core gated nur darüber. Ninox: `clickAction: false` → nicht klickbar; sonst Default-Popup über `itemId`.
- **Filter values**: Extract filter variables BEFORE the `(select ...)` query, never inline.
- **Sections with different data**: Use `for section in sections do...end`, NOT a static array.
- **empty**: Off by default. Opt-in pill: `empty: { enabled: true, value: "Keine Einträge", backgroundColor: "#fff", fontColor: "#888", fontWeight: 400 }` on the board or a swimlane.

# Custom Kanban

![](https://framerusercontent.com/images/mHlFDpfOkhxieybe820lNfJs.png)

El Kanban representa datos de una tabla (tarjetas Kanban) en un estado determinado (en las swimlanes). Para ello, creas como es habitual una variable ***data***, que luego emites en la función global ***arcCustomKanban***. Hay dos formas de crear un Kanban:

- **dinámica** (las swimlanes se refieren a una lista/tabla/bucle for)
- **manual** (las swimlanes se definen manualmente)

## Código de aplicación dinámico


```javascript
let current := this;
let listFirmen := (select Firmen);
let listStates := (select Status_Leads);
let data := {
        uniqueId: "Kanban individuell",
        height: "600px",
        collapsible: true,
        showScrollbar: true,
        swimlanes: listStates.[{
                title: Titel,
                recordId: number(Nr),
                backgroundColorHeader: text(color(Farbe)),
                backgroundColorBody: "",
                fontColor: "",
                minWidth: "",
                amount: let id := Nr;
                cnt(listFirmen[number(Status) = number(id)]),
                items: let id := Nr;
                listFirmen[number(Status) = number(id)].[{
                    itemId: Nr,
                    fieldId: "D",
                    clickAction: false,
                    dragAction: true,
                    paddingX:",
                    paddingY: "",
                    borderPosition: "",
                    borderColor: "",
                    borderWidth: "",
                    title: Name,
                    subtitle: "Kunden-Nr.:" + Nr,
                    value: arcCustomProgressBar({
                            uniqueId: "progress" + Nr,
                            title: "",
                            width: "100%",
                            fontSize: "",
                            fontColor: "",
                            backgroundColor: "",
                            progressColor: "",
                            valueTotal: stateTotal,
                            valueProgress: stateCurrent,
                            valueText: stateCurrent + "/" + stateTotal
                                        })
                    }]
            }]
    };
arcCustomKanban(data)
```

### Configurar variables


```javascript
let current := this; // Definiert diesen Record
let listFirmen := (select Firmen); // Definiert die Tabelle für die darzustellenden Inhalte
let listStates := (select Status_Leads); // Definiert die Liste für die Swimlanes
```

### Ajustes generales en *data*

***uniqueId*** es la denominación individual de tu Kanban. Asegúrate de asignar aquí un título único. Esto es importante si quieres representar varios Kanbans en una página y que tus ajustes de estilo no se sobrescriban entre sí.


```javascript
uniqueId: "Kanban individuell",
```

***height*** define la altura de tu Kanban.


```javascript
height: "600px", // Pixel-Werte
height: "auto", // Passt die Höhe an die Inhalte an.
height: "100%", // Passt sich der Höhe des Funktionsfeldes an.
height: "", // Fallback-Wert: 100%
```

Con ***collapsible*** puedes configurar que el usuario pueda contraer o expandir las swimlanes con un clic en el icono de contraer (caret-up).


```javascript
collapsible: true, // Aktiviert die Funktion
collapsible: "", // Fallback-Wert = "false"
```

Con ***showScrollbar*** se puede mostrar la barra de scroll horizontal para todo el Kanban. Esto ayuda especialmente a los usuarios sin trackpad o tablet.


```javascript
showScrollbar: true, // Scrollbar wird eingeblendet
showScrollbar: false, // keine Anzeige der Scrollbar
showScrollbar: "", // default: false
```

### Ajustes de swimlane en *data*

El parámetro swimlane define la representación de cada una de las columnas de tu Kanban. Estas se definen dentro de los corchetes y llaves.


```javascript
swimlanes: listStates.[{

            }]
```

***title*** define el título de cada swimlane. En este ejemplo puede ser el título de la tabla listStates - es decir, dinámico.


```javascript
title: Titel, // Ninox-Feld im Textformat.
title: "Hans" // Text in ", wenn das Kanban manuell angelegt ist
title: "" // Kein Fallback hinterlegt.
```

***recordId*** define el registro de la lista dinámica que has definido previamente. Aquí: listStates.


```javascript
recordId: number(Nr), // Nr des jeweiligen Records aus der Liste
```

***backgroundColorHeader*** define el color de fondo de la cabecera de cada swimlane.


```javascript
backgroundColorHeader: text(color(Farbe)), // Ninox Feld , das Farbe referenziert (HEX Wert ausgibt)
backgroundColorHeader: "#000", // HEX Wert in "
backgroundColorHeader: " ,// Fallback-Wert: #8594c1
```

***backgroundColorBody ***define el color de fondo del cuerpo (Body) de la swimlane.


```javascript
backgroundColorBody: text(color(Farbe)), // Ninox Feld , das Farbe referenziert (HEX Wert ausgibt)
backgroundColorBody: "#000", // HEX Wert in "
backgroundColorBody: "", // Fallback-Wert: #f4f7ff
```

***fontColor*** define el color de fuente de la cabecera.


```javascript
fontColor: "#000", // Hex-Wert in "
fontColor: "", // Fallback-Wert: #fff
```

***minWidth*** indica el ancho mínimo de las swimlanes. Esto evita que las swimlanes se compriman cada vez más en pantallas pequeñas. Así tus contenidos siempre se muestran bien legibles, ya que se puede desplazar hacia la derecha.


```javascript
minWidth: "300px", // Pixel-Wert in "
minWidth: "", // Fallback-Wert: 150px
```

***empty*** muestra una pill en las columnas vacías. **Por defecto: desactivado.** En el board para todas las columnas, o por swimlane (sobrescribe el board). `true` / `"true"` es el antiguo interruptor abreviado.


```javascript
empty: {
    enabled: true,
    value: "Keine Einträge",
    backgroundColor: "#fff",
    fontColor: "#888888",
    fontWeight: 400
}
empty: true
empty: "" // Default: keine Pill
```

***amount*** define qué cantidad se muestra en la cabecera de la swimlane. Número, string HTML o widget anidado — igual que `title`. Vacío / omitido oculta la burbuja. Un **número** se actualiza inmediatamente al mover una tarjeta. **HTML o un widget** permanece sin cambios (sin contador automático) y solo se actualiza con el siguiente reload de Ninox.


```javascript
amount: let id := Nr; cnt(list[number(Status) = number(id)]),
amount: "<b>" + cnt(list[number(Status) = number(id)]) + "</b>",
amount: "" // Kein Fallback-Wert. Die Amount-Bubble wird in diesem Fall ausgeblendet.
```

### Ajustes de Item (Cards) dentro de *swimlanes*

El parámetro items define la representación de tus tarjetas dentro de la swimlane. Estos se definen dentro de los corchetes y llaves.


```javascript
items: let id := Nr;
listFirmen[number(Status) = number(id)].[{

  }]
```

***itemId*** define el registro de la lista de items. aquí: listFirmen.


```javascript
 itemId: Nr, // Record-Id
```

***fieldId*** define el campo que debe cambiar al pasar de swimlane. En la mayoría de los casos es el estado.


```javascript
fieldId: "D", // Field ID findest du mit dem arcFieldFinder heraus
```

***clickAction*** controla el clic sobre la tarjeta. Compatible con Legacy:

- `false` → sin clic
- `true` / omitir / `""` → abre el registro mediante `popupRecord` (`itemId`)
- Objeto (o array) → una acción como en Calendar/Layout (p. ej. `{ type: "popup", recordId: Nr }`)


```javascript
 clickAction: false, // Deaktiviert die Klick-Aktion
 clickAction: true, // Fallback: popupRecord(itemId)
 clickAction: {
   type: "popup",
   recordId: Nr
 },
 clickAction: {
   type: "update",
   recordId: helperRecordId,
   fieldId: "A",
   value: Nr
 },
```

***actions*** (Array) — vía preferida para varias acciones en el clic. Tiene prioridad sobre `clickAction` (excepto `clickAction: false`). Mismos tipos de acción que Calendar/Layout (`popup`, `update`, `openRecord`, `create`, …).


```javascript
 actions: [{
   type: "popup",
   recordId: Nr
 }, {
   type: "update",
   recordId: helperRecordId,
   fieldId: "A",
   value: Nr
 }],
```

***dragAction*** define si el usuario puede mover la tarjeta mediante drag and drop.


```javascript
dragAction: false, // Deaktiviert die Drag & Drop Funktion.
dragAction: "", // Fallback-Wert: true
```

***paddingX*** define el espacio entre el borde y el contenido a la derecha e izquierda dentro de la tarjeta.


```javascript
paddingX: "10px" // Pixel-Wert in "
paddingX:",  // Fallback-Wert: 12px
```

***paddingY*** define el espacio entre el borde y el contenido arriba y abajo dentro de la tarjeta.


```javascript
paddingY: "10px" // Pixel-Wert in "
paddingY: "", // Fallback-Wert: 12px
```

***borderPosition*** define si quieres mostrar un borde unilateral en la tarjeta. Este podría, mediante el color, representar otro atributo/categoría de tus contenidos (por ejemplo, Activo / Inactivo)


```javascript
borderPosition: "left", // Border auf der linken Seite
borderPosition: "right", // Border auf der rechten Seite
borderPosition: "top", // Border auf der oberen Seite
borderPosition: "bottom", // Border auf der unteren Seite
borderPosition: "", // Fallback-Wert: keine border
```

***borderColor*** define el color de tu borde.


```javascript
borderColor: if aktiv=true then "#c5f2b3" else "#ccc"// HEX-Wert in "
borderColor: "", // Fallback-Wert:
```


```javascript
borderWidth: "1px", // Pixel-Wert in "
borderWidth: "", // Fallback-Wert:
```

***title*** muestra el título superior en la tarjeta y aparece en negrita.


```javascript
title: Name, // Ninox-feld in Text-Format
title: "" // Kein Fallback
```


```javascript
subtitle: "Kunden-Nr.:" + Nr, // Text und/oder Ninox Felder in Textformat
subtitle: arcCustomLayout({ uniqueId: "sub-" + Nr, embedded: true, ... }), // gleiches Slot wie value
subtitle: "", // Kein Fallback
```

Con ***value*** puedes diseñar tu tarjeta de forma tan individual como quieras. Aquí puedes trabajar con texto o integrar cualquier otro widget. Por ejemplo, puedes usar [arcCustomLayout](/documentation/custom-layout) para crear tarjetas más complejas o simplemente insertar una barra de progreso con [arcCustomProgressBar](/documentation/progress-bar).


```javascript
value: "Hier steht Text" // Texte oder Werte aus Ninox-Feldern
value: arcCustomProgressBar({
            uniqueId: "progress" + Nr,
            title: "",
            width: "100%",
            fontSize: "",
            fontColor: "",
            backgroundColor: "",
            progressColor: "",
            valueTotal: stateTotal,
            valueProgress: stateCurrent,
            valueText: stateCurrent + "/" + stateTotal
        }) // Andere Widgets
value: "", // Kein Fallback

```
