Skip to content

Commit 9d0c30c

Browse files
committed
fix: side-by-side field alignment with uneven label heights
Replace align-items-start with fields-aligned-row marker class so columns stretch to equal height (default flex behaviour). The existing margin-top:auto CSS then correctly pushes inputs to align at a consistent vertical position regardless of label wrapping. Bump version to 0.63.1.
1 parent c89d7f8 commit 9d0c30c

4 files changed

Lines changed: 31 additions & 20 deletions

File tree

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.63.1] - 2026-04-02
11+
12+
### Fixed
13+
- **Side-by-side field alignment** — inputs, labels, and help text now align
14+
correctly when paired half/third/fourth-width fields have labels of
15+
different heights (e.g. one wraps to two lines). Replaced
16+
`align-items-start` with a `fields-aligned-row` marker class that uses the
17+
default `align-items-stretch` behaviour, allowing `margin-top: auto` on
18+
inputs to push them to a consistent vertical position.
19+
1020
## [0.63.0] - 2026-04-02
1121

1222
### Added

django_forms_workflows/forms.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ def __init__(
286286
Field(next_field.field_name),
287287
css_class=f"col-md-6 field-wrapper field-{next_field.field_name}",
288288
),
289-
css_class="align-items-start",
289+
css_class="fields-aligned-row",
290290
)
291291
)
292292
i += 2
@@ -321,7 +321,7 @@ def __init__(
321321
)
322322
for f in group
323323
],
324-
css_class="align-items-start",
324+
css_class="fields-aligned-row",
325325
)
326326
)
327327
else:
@@ -1784,7 +1784,7 @@ def _build_layout_fields(self, field_defs):
17841784
Field(next_field.field_name),
17851785
css_class=f"col-md-6 field-wrapper field-{next_field.field_name}",
17861786
),
1787-
css_class="align-items-start",
1787+
css_class="fields-aligned-row",
17881788
)
17891789
)
17901790
i += 2
@@ -1818,7 +1818,7 @@ def _build_layout_fields(self, field_defs):
18181818
)
18191819
for f in group
18201820
],
1821-
css_class="align-items-start",
1821+
css_class="fields-aligned-row",
18221822
)
18231823
)
18241824
else:

django_forms_workflows/static/django_forms_workflows/css/forms.css

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,31 @@
33
═══════════════════════════════════════════════════════════════════════════ */
44

55
/* ── Side-by-side field alignment ────────────────────────────────────────
6-
When two half-width fields sit in a .row, the shorter one needs to
7-
bottom-align its input with the taller one regardless of label length,
8-
help-text presence, or wrapped text. We use flex-column + stretch so
9-
the label area grows evenly and the input sits at a consistent position. */
10-
11-
.row.align-items-start > [class*="col-"] > .mb-3,
12-
.row.align-items-start > .field-wrapper > .mb-3 {
6+
When two or more fields sit in a .row.fields-aligned-row, columns
7+
stretch to equal height (the default flex behaviour). Each .mb-3
8+
wrapper becomes a flex column so the label area grows evenly and
9+
the input sits at a consistent vertical position regardless of
10+
label length, help-text presence, or wrapped text. */
11+
12+
.row.fields-aligned-row > [class*="col-"] > .mb-3,
13+
.row.fields-aligned-row > .field-wrapper > .mb-3 {
1314
display: flex;
1415
flex-direction: column;
1516
height: 100%;
1617
}
17-
.row.align-items-start > [class*="col-"] > .mb-3 > label,
18-
.row.align-items-start > .field-wrapper > .mb-3 > label {
18+
.row.fields-aligned-row > [class*="col-"] > .mb-3 > label,
19+
.row.fields-aligned-row > .field-wrapper > .mb-3 > label {
1920
flex-shrink: 0;
2021
}
21-
.row.align-items-start > [class*="col-"] > .mb-3 > .form-control,
22-
.row.align-items-start > [class*="col-"] > .mb-3 > .form-select,
23-
.row.align-items-start > .field-wrapper > .mb-3 > .form-control,
24-
.row.align-items-start > .field-wrapper > .mb-3 > .form-select {
22+
.row.fields-aligned-row > [class*="col-"] > .mb-3 > .form-control,
23+
.row.fields-aligned-row > [class*="col-"] > .mb-3 > .form-select,
24+
.row.fields-aligned-row > .field-wrapper > .mb-3 > .form-control,
25+
.row.fields-aligned-row > .field-wrapper > .mb-3 > .form-select {
2526
margin-top: auto; /* push the input to the bottom of the cell */
2627
}
2728
/* Help text sits *after* the input and shouldn't shift it up */
28-
.row.align-items-start > [class*="col-"] > .mb-3 > .form-text,
29-
.row.align-items-start > .field-wrapper > .mb-3 > .form-text {
29+
.row.fields-aligned-row > [class*="col-"] > .mb-3 > .form-text,
30+
.row.fields-aligned-row > .field-wrapper > .mb-3 > .form-text {
3031
flex-shrink: 0;
3132
min-height: 1.4em; /* reserve space even when empty for alignment */
3233
}

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "django-forms-workflows"
3-
version = "0.63.0"
3+
version = "0.63.1"
44
description = "Enterprise-grade, database-driven form builder with approval workflows and external data integration"
55
license = "LGPL-3.0-only"
66
readme = "README.md"

0 commit comments

Comments
 (0)