Files
bin/espocrm-table-var-col_claude-code-instructions.md
mkt cebe829dcd Add README, customization snapshot, and snapshot/restore tooling
Provisioning now restores all GUI customizations on reset+reprovision:

- create_pod_espocrm.sh: deploy the version-controlled espocrm-custom/ tree
  (CTag entity, layouts, i18n, clientDefs, custom views, custom CSS) into the
  pod, then chown www-data and rebuild. Replaces the earlier inline CSS-only
  step. Adds a live-phase cache rebuild so customizations and the client
  cacheTimestamp are refreshed on every run.
- espocrm-custom/: snapshot of custom/ and client/custom/ (source of truth).
- snapshot_espocrm_custom.sh: refresh the snapshot from a running pod.
- readme.md: usage, first-time host setup, image-update and reset workflows.
- Include the task/instruction notes and plan.md for reference.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 16:51:02 +02:00

4.9 KiB

EspoCRM Customization: Variable Column Widths for Markdown Tables

Instructions for Claude Code. Goal: integrate a custom CSS file into the EspoCRM provisioning so that Markdown tables in text fields get content-based column widths instead of equal fixed widths. The EspoCRM installation is generated by a shell script into a Podman pod, so both files below must be created by the provisioning script — manual edits inside the pod would be lost on the next provisioning run.

Problem and Root Cause

EspoCRM renders Markdown in text fields (e.g. Opportunity → Beschreibung) inside .complex-text containers. The core stylesheet contains this rule (verified live on this instance, EspoCRM 9.3.8, 2026-06-06):

.alert table, .alert > .message table, .complex-text table,
.confirm-message table, .popover-content table {
    table-layout: fixed;
    width: 100%;
}

table-layout: fixed distributes the table width equally across all columns regardless of content. Measured effect on a 4-column table in a record detail view: every column 200 px wide, causing short columns (Nr., Bew.) to waste space and the long Anforderung column to wrap into unnecessarily tall rows.

With table-layout: auto, columns size to their content. Verified by live style injection on the test record: column widths became 37 / 112 / 49 / 604 px — exactly the desired result.

Solution: EspoCRM Custom CSS Mechanism

EspoCRM's official mechanism for custom stylesheets (docs): register the CSS file in the cssList metadata. Both involved directories (client/custom/, custom/) are upgrade-safe — EspoCRM upgrades do not touch them. The CSS filename is arbitrary; we use the declarative name table-var-col.css.

File 1 (new): <espocrm-root>/client/custom/css/table-var-col.css

/**
 * Variable column widths for Markdown tables in text fields.
 *
 * EspoCRM core CSS forces `table-layout: fixed; width: 100%` on
 * `.complex-text table`, which makes all columns equally wide.
 * `auto` lets columns size to content instead.
 *
 * Registered via custom/Espo/Custom/Resources/metadata/app/client.json (cssList).
 */
.complex-text table {
    table-layout: auto !important;
    width: auto !important;
    max-width: 100% !important;
}

Notes:

  • The selector deliberately targets only .complex-text (text fields on record views), not the alert/popover tables of the core rule.
  • !important guards against load-order variations; cssList entries are appended after the theme stylesheet, but this makes the override robust either way.

File 2 (new or merge): <espocrm-root>/custom/Espo/Custom/Resources/metadata/app/client.json

{
    "cssList": [
        "__APPEND__",
        "client/custom/css/table-var-col.css"
    ]
}

IMPORTANT — merge, do not overwrite: This instance already has GUI customizations. If client.json already exists, append the path to the existing cssList array (keeping "__APPEND__" as its first element) and leave all other keys untouched. Check first.

Integration into the Provisioning Script

  1. Locate where the script already injects EspoCRM GUI customizations and follow the same convention (e.g. podman cp, volume mount, or heredoc).
  2. Create both files after the EspoCRM installation step.
  3. Match file ownership/permissions to the other EspoCRM application files (typically the webserver user inside the container, e.g. www-data:www-data). The CSS file must be readable by the webserver.
  4. Clear the cache afterwards — cssList is metadata and is cached:
podman exec <container> php /var/www/html/clear_cache.php
# or, if the script already performs a rebuild:
podman exec <container> php /var/www/html/rebuild.php

(Adapt container name and EspoCRM root path to the script's actual values.)

Testing

  1. Persistence test (the actual requirement): re-run the provisioning script from scratch, then verify both files exist inside the pod: podman exec <container> ls -l /var/www/html/client/custom/css/table-var-col.css /var/www/html/custom/Espo/Custom/Resources/metadata/app/client.json
  2. Log in to the CRM, hard-reload (Ctrl+F5). In DevTools → Network, filter for table-var-col → the stylesheet must load with HTTP 200.
  3. Open the test record (4-column Markdown table in Beschreibung): https://crm.creature-go.com/#Opportunity/view/6a23fc99e2391e7be
  4. Visual check: columns Nr., Einordnung, Bew. at minimal width, Anforderung takes the remaining space; rows are one to two lines instead of uniformly tall.
  5. Programmatic check in the DevTools console:
getComputedStyle(document.querySelector('.complex-text table')).tableLayout
// expected: "auto"  (without the fix: "fixed")
  1. Regression check: open a record whose description contains no table and one with other Markdown (lists, headings) — rendering must be unchanged. Existing GUI customizations must still be active.