Skip to content

g:flashMessages tag#15560

Open
codeconsole wants to merge 2 commits intoapache:7.1.xfrom
codeconsole:7.1.x-flashMessages
Open

g:flashMessages tag#15560
codeconsole wants to merge 2 commits intoapache:7.1.xfrom
codeconsole:7.1.x-flashMessages

Conversation

@codeconsole
Copy link
Copy Markdown
Contributor

@codeconsole codeconsole commented Apr 6, 2026

Flash Messages Tag (g:flashMessages)

Introduces a new <g:flashMessages /> tag that renders flash.message, flash.error, and flash.warning as Bootstrap
5 dismissible alerts with appropriate styling (success, danger, and warning respectively).

The tag automatically prevents duplicate rendering -- if called in both a page and its layout, only the first invocation produces
output. All flash content is HTML-encoded to prevent XSS.

The default layout (main.gsp) and all scaffolding templates now use this tag. If your application has custom views that render
flash messages manually, you can replace the boilerplate:

<%-- Before --%>
<g:if test="${flash.message}">
    <div class="alert alert-primary" role="alert">${flash.message}</div>
</g:if>                                                                                                                             
 
<%-- After --%>                                                                                                                     
<g:flashMessages />                                             

The tag supports optional attributes for customizing CSS classes, icons, ARIA role, and dismissibility. See the flashMessages tag
reference for full details.

This tag has been introduced to all default layouts so that every page has automatic access to displaying flash.* messages. Multiple <g:flashMessages /> are supported, but the first one rendered is prioritized. Because of this, if a view (e.g.: scaffold view) has a <g:flashMessages />, that flash.message location is prioritized over the layout location.

Purpose

Renders flash.message, flash.error, and flash.warning as dismissible Bootstrap alert divs with appropriate styling.
Automatically prevents duplicate rendering when used in both pages and layouts.

Examples

Basic usage in a view:

<g:flashMessages />

In a layout (safe to use alongside page-level usage -- the tag skips rendering if already called):

<g:flashMessages />                                                         
<g:layoutBody/>

Non-dismissible alerts:

<g:flashMessages dismissible="false" />

Custom ARIA role:

<g:flashMessages role="status" />                                           

Custom styling for success messages:

<g:flashMessages messageClass="alert alert-info" messageIcon="bi bi-info-circle me-2" />

Setting flash messages in a controller:

// Success message (renders as green alert)
flash.message = "Book '${book.title}' saved successfully."                                                                          
                                                                                                                                    
// Error message (renders as red alert)                                                                                             
flash.error = "Unable to delete the record."                                                                                        
                                                                                                                                    
// Warning message (renders as yellow alert)
flash.warning = "You have unsaved changes."                                                                                         

Description

The flashMessages tag renders any combination of flash.message, flash.error, and flash.warning as Bootstrap 5 alert divs.
Each flash key maps to a different alert style:

Flash Key Default Alert Class Default Icon
flash.message alert alert-success alert-dismissible fade show bi bi-check-circle me-2
flash.error alert alert-danger alert-dismissible fade show bi bi-exclamation-triangle me-2
flash.warning alert alert-warning alert-dismissible fade show bi bi-exclamation-circle me-2

The tag automatically sets a _flashRendered request attribute after rendering. On subsequent calls within the same request, the
tag detects this attribute and outputs nothing. This allows both pages and layouts to include <g:flashMessages /> without
producing duplicate alerts -- whichever renders first wins.

All flash message content is HTML-encoded to prevent XSS.

Attributes

  • messageClass (optional) - CSS class for flash.message alerts. Default: alert alert-success alert-dismissible fade show
  • messageIcon (optional) - Icon class for flash.message alerts. Default: bi bi-check-circle me-2
  • errorClass (optional) - CSS class for flash.error alerts. Default: alert alert-danger alert-dismissible fade show
  • errorIcon (optional) - Icon class for flash.error alerts. Default: bi bi-exclamation-triangle me-2
  • warningClass (optional) - CSS class for flash.warning alerts. Default: alert alert-warning alert-dismissible fade show
  • warningIcon (optional) - Icon class for flash.warning alerts. Default: bi bi-exclamation-circle me-2
  • role (optional) - ARIA role for alert divs. Default: alert
  • dismissible (optional) - Whether to show a close button. Default: true

@jdaugherty
Copy link
Copy Markdown
Contributor

I know we ship with bootstrap as an example, but end grails applications technically don't have to use it. Do we default style any of other tags this way?

@jamesfredley
Copy link
Copy Markdown
Contributor

Tag(s) What they emit CSS classes
g:textField, g:form, g:select, g:datePicker, g:link Plain HTML (<input>, <form>, <a>) None unless user passes class attribute
g:paginate, g:sortableColumn Links/spans Generic classes: prevLink, nextLink, step, currentStep, sortable, sorted asc
g:renderErrors, g:renderException Error markup Generic classes: error-details, stack
f:field, f:table (fields plugin) Scaffolding fields Generic classes: fieldcontain, property-list, required, even/odd

All of these are framework-agnostic class names - none reference Bootstrap (alert, btn, form-control), Tailwind, or any other CSS framework.

The classes are overridable via attributes (messageClass, messageIcon, etc.), but the defaults themselves are Bootstrap 5-specific.

@codeconsole
Copy link
Copy Markdown
Contributor Author

codeconsole commented Apr 7, 2026

I know we ship with bootstrap as an example, but end grails applications technically don't have to use it. Do we default style any of other tags this way?

@jdaugherty if you look at all the locations where this tag is being used (scaffold and default layouts), it is replacing bootstrap code.

                <g:if test="\${flash.message}">
                    <div class="alert alert-primary" role="alert"><i class="bi-info-circle"></i> \${flash.message}</div>
                </g:if>

@jamesfredley all those tags actually reference proprietary grails classes that end users shouldn't be using. My plan was eventually to swap those defaults out to bootstrap classes considering all those hardcoded grails classes are no longer used and the css has since been deleted.

motivation behind this PR

Flash messages should fallback to being displayed in the layout. That way utilizing flash.message in a controller will always result in the flash message being displayed. There is no requirement for utilizing this tag lib, but, like the other g: tags, the classes are overridable.

@matrei
Copy link
Copy Markdown
Contributor

matrei commented Apr 7, 2026

Just thinking out loud: Could the CSS class defaults be set (and overridden) in configuration? Then we could default to the Bootstrap theme classes in grails-gsp configuration and it would be easy to override "globally" in the application without having to set the classes explicitly in source.

@jdaugherty
Copy link
Copy Markdown
Contributor

Another possibility is to push a custom tag lib with the Scaffolding plugin. I don't think we should be putting css framework specific classes in grails-gsp. I'm ok to do that in scaffolding since there's precedence there.

@sbglasius
Copy link
Copy Markdown
Contributor

@codeconsole My suggestion is to make generic output, and follow the way the fields plugin works.

Have a structure like:

grails-app
- views
  - _flash
    - _message.gsp
    - _error.gsp
    - _warning.gsp

And if they are not defined revert back to sensible default values like fields

@codeconsole
Copy link
Copy Markdown
Contributor Author

Just thinking out loud: Could the CSS class defaults be set (and overridden) in configuration? Then we could default to the Bootstrap theme classes in grails-gsp configuration and it would be easy to override "globally" in the application without having to set the classes explicitly in source.

@matrei
We could, and I am not opposed to doing that, but how many locations do you actually anticipate using this tag?
1 layout and a couple of layouts? if so, you just override the classes in the tag <g:flashMessages messageClass="alert alert-info" />

Of course the other option is don't use the tag at all.

@codeconsole
Copy link
Copy Markdown
Contributor Author

codeconsole commented Apr 7, 2026

Another possibility is to push a custom tag lib with the Scaffolding plugin. I don't think we should be putting css framework specific classes in grails-gsp. I'm ok to do that in scaffolding since there's precedence there.

@jdaugherty isn't there already css framework specific classes in virtually every other grails tag?

This really has nothing to do with scaffolding. It targets flash.messages

@jdaugherty
Copy link
Copy Markdown
Contributor

jdaugherty commented Apr 7, 2026

@jdaugherty isn't there already css framework specific classes in virtually every other grails tag?

This really has nothing to do with scaffolding. It targets flash.messages

Doing some analysis with AI: it thinks that bootstrap classes aren't hard coded today - only the basic grails classes:

Grails TagLib CSS Classes Audit

An inventory of all hardcoded CSS classes in shipped Grails tag libraries.

UrlMappingTagLib — Pagination & Sorting

File: grails-gsp/plugin/src/main/groovy/org/grails/plugins/web/taglib/UrlMappingTagLib.groovy

<g:paginate>

CSS Class Overridable? Notes
prevLink No Applied to the previous page link
nextLink No Applied to the next page link
step No Applied to each page number link
step gap No Hardcoded <span class="step gap">..</span> for ellipsis gaps
currentStep Yes (activeClass attr) Default class for the active/current page

<g:sortableColumn>

CSS Class Overridable? Notes
sortable No Always added to the column
sorted No Added when column is the active sort column
asc / desc No Sort direction appended as a class alongside sorted

FormFieldsTagLib — Field Wrappers

File: grails-fields/grails-app/taglib/grails/plugin/formfields/FormFieldsTagLib.groovy

<f:field>

CSS Class Overridable? Notes
fieldcontain Yes (class attr) Default wrapper div class
error Yes (invalidClass attr) Added when the field has validation errors
required Yes (requiredClass attr) Added when the field is required
required-indicator No Hardcoded on <span> containing *

RenderTagLib — Error/Exception Display

File: grails-gsp/grails-web-gsp-taglib/src/main/groovy/org/grails/plugins/web/taglib/RenderTagLib.groovy

<g:renderException>

CSS Class Overridable? Notes
error-details Yes (detailsClass attr) Default class on the <dl> element
stack Yes (stackClass attr) Default class on the <pre> element for stack traces

Summary

TagLib Tag Total Classes Overridable Not Overridable
UrlMappingTagLib paginate 5 1 4
UrlMappingTagLib sortableColumn 3 0 3
FormFieldsTagLib field 4 3 1
RenderTagLib renderException 2 2 0
Total 14 6 8

Assessment

  • No CSS framework dependency. The hardcoded class names (sortable, step, error, etc.) are semantic/functional names. They do not correspond to Bootstrap, Tailwind, or any other CSS framework.
  • 8 of 14 classes are not overridable. The paginate and sortableColumn tags in UrlMappingTagLib are the primary concern, with 7 non-overridable classes between them. Users must target these specific class names in their stylesheets.
  • Most FormFieldsTagLib and RenderTagLib defaults can be replaced via tag attributes.
  • CustomTagLib.groovy in grails-test-examples/ contains Bootstrap-like patterns (panel, alert, badge, progress-bar) but is a test fixture, not part of the shipped framework.

@codeconsole
Copy link
Copy Markdown
Contributor Author

codeconsole commented Apr 7, 2026

Doing some analysis with AI: it thinks that bootstrap classes aren't hard coded today - only the basic grails classes:

@jdaugherty what is the difference between a bootstrap css class or a custom grails class that requires importing an additional css rule? At the end of the day, it is just a css class. If you don't have bootstrap, you could just write your own rule for it or write no rule in which the css classes would have no effect.

I would much rather see well thought out bootstrap classes than css classes that don't even exist anymore in the codebase.

My original plan for 8 was to swap all the deprecated default grails class names with bootstrap ones.

@jdaugherty
Copy link
Copy Markdown
Contributor

@codeconsole This is for 7.1 though. I'd agree with you if we were on bootstrap exclusively. Although, I debate if we should do that with css frameworks like tailwind. For 7.1, I think we should move it to it's own tag lib or make it configurable.

* @attr role ARIA role for alert divs (default: 'alert')
* @attr dismissible Whether to show a close button (default: true)
*/
Closure flashMessages = { attrs ->
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discussed this in the weekly and we need to release 7.1 soon. For a quick resolution here and to make it in 7.1, we should either make this configurable at the app level or move it to the scaffolding project with a custom tag lib. Otherwise, we can revisit this in 8.0.

@bito-code-review
Copy link
Copy Markdown

The comment proposes two quick fixes for the hardcoded Bootstrap 5 styling in the new flashMessages tag to meet the 7.1 release: 1) Add app-level config for CSS classes and icons (e.g., via application.yml), or 2) Implement as a custom tag in the scaffolding project instead of core. This avoids delaying the release while allowing flexibility for non-Bootstrap apps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

5 participants