Skip to content

Feature: attachment input - #60

Merged
sfnelson merged 22 commits into
mainfrom
feature/attachment-input
Aug 3, 2026
Merged

Feature: attachment input#60
sfnelson merged 22 commits into
mainfrom
feature/attachment-input

Conversation

@sfnelson

@sfnelson sfnelson commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Upgrade notes (1.x → 2.0)

This release replaces the image/document file fields with an ActiveStorage-backed
attachment field: preview figures, drag-and-drop, async direct uploads with retry,
removal, and a complete no-JavaScript fallback. govuk_image_field and
govuk_document_field keep their names and render the new field by default.

Required changes

  • Attachment values must be ActiveStorage. govuk_image_field /
    govuk_document_field now require a has_one_attached / has_many_attached
    attribute and raise ArgumentError otherwise (previously they rendered a plain
    enhanced input for e.g. form objects). For plain file uploads, switch to
    govuk_file_field.

  • Required attachments need a presence validation. Removal is always offered —
    the optional: argument no longer does anything. A required attachment is
    guarded by its model validation, not by the UI hiding removal.

  • Wire the JavaScript with GOVUK.start. The attachment and file-upload
    enhancements are Stimulus-powered. Register the gem on your Stimulus application
    from your bundle — this replaces the 1.x application.load(govuk) extension
    wiring, which now raises a TypeError at boot (the default export is no longer
    the controller definitions array):

    import GOVUK from "@katalyst/govuk-formbuilder";
    GOVUK.start(application);

    start registers the controllers and keeps the page enhanced for the whole
    session, including across Turbo visits. If you're not running Stimulus, or you
    want the GOV.UK enhancements kept separate from your application, render
    <%= govuk_formbuilder_init %> at the end of <body> instead — it enhances
    per page render, registering the controllers on a gem-owned Stimulus
    application. Without either wiring, attachment fields fail open to a native
    file input — functional, but no previews, drag-and-drop, or direct uploads.

  • Delete Turbo re-init wiring. Enhancement now observes the DOM: lazy frames,
    stream inserts, and morphs re-enhance automatically. Remove any turbo:render /
    turbo:frame-load re-initialisation listeners (the turbo:render variant never
    worked); repeat calls are harmless no-ops.

Behaviour changes to review

  • Custom and translated strings now reach the UI. The file fields' text options
    and the Rails i18n vocabulary (katalyst.govuk.attachment.*) are now read by the
    JavaScript. Previously the documented text options rendered but were never read,
    so announcements were always English — review any strings you set.
  • Dropped files are no longer mime-filtered on the client. Legacy silently
    discarded drops outside mime_types; now accept remains a picker courtesy and
    the server's validations are the authority. Add model validations if you relied
    on the client filter.
  • Brand affects CSS classes only. Stimulus identifiers and data-* wiring are
    always govuk-* — previously a non-default brand rendered controller names the
    JS never matched, so those controllers never connected. The gem's compiled CSS
    stays govuk-prefixed; a custom brand presumes a consumer-supplied frontend build.
  • label:, caption:, hint:, and form_group: on image/document fields are now
    forwarded (previously captured and silently dropped).
  • Preview thumbnails are generated lazily and the transformation is configurable:
    GOVUKDesignSystemFormBuilder.config.attachment_preview_representation
    (default: resize_to_fill: [256, 256] — a crisp centre-cropped square, sized
    with leeway for dense displays). The square preview box is filled with
    object-fit: cover; a consumer wanting whole-image contain previews
    overrides the representation too.

JavaScript dependencies

The module imports @hotwired/stimulus and @rails/activestorage. Importmap apps
get the gem's pins automatically; jsbundling apps must provide both packages at
runtime — the wiring is the same GOVUK.start(application), from your own bundle.

Transitional escape hatch

The legacy field implementations remain in the gem behind a flag, to stage a
migration — the flag and the legacy code will be removed together in a future
release:

GOVUKDesignSystemFormBuilder.config.use_legacy_file_fields = true # default false

@sfnelson
sfnelson marked this pull request as draft July 23, 2026 04:51
@sfnelson
sfnelson force-pushed the feature/attachment-input branch 6 times, most recently from 033d057 to f774554 Compare July 28, 2026 23:56
@sfnelson
sfnelson force-pushed the feature/attachment-input branch 4 times, most recently from 5a3b5a8 to 17ec2e9 Compare July 31, 2026 13:13
@sfnelson
sfnelson marked this pull request as ready for review July 31, 2026 13:13
@sfnelson
sfnelson force-pushed the feature/attachment-input branch from 17ec2e9 to b035fe9 Compare July 31, 2026 13:49
@sfnelson
sfnelson force-pushed the feature/attachment-input branch from b035fe9 to 204cd1e Compare August 2, 2026 11:27
@sfnelson
sfnelson force-pushed the feature/attachment-input branch from 204cd1e to 68e966e Compare August 3, 2026 03:01
@sfnelson
sfnelson merged commit 2ba0ca3 into main Aug 3, 2026
1 check passed
@sfnelson
sfnelson deleted the feature/attachment-input branch August 3, 2026 10:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant