////
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
////

Like https://www.oracle.com/java/technologies/jspt.html[Java Server Pages] (JSP), GSP supports the concept of custom tag libraries. Unlike JSP, Grails' tag library mechanism is simple, elegant and completely reloadable at runtime.

Quite simply, to create a tag library create a Groovy class that ends with the convention `TagLib` and place it within the `grails-app/taglib` directory:

[source,groovy]
----
class SimpleTagLib {

}
----

Now create tags using methods. Methods with the conventional `Map attrs`, `Closure body`, and `Map attrs, Closure body` signatures are discovered as tags automatically:

[source,groovy]
----
class SimpleTagLib {
    def simple(Map attrs) {
        out << attrs.name
    }
}
----

Closure field-style tags are still supported for backward compatibility, but method-based tags are the recommended syntax.

The `attrs` parameter is a `Map` of the tag attributes, while the `body` parameter is the tag body closure:

[source,groovy]
----
class SimpleTagLib {
    def emoticon(Map attrs, Closure body) {
       out << body() << (attrs.happy == 'true' ? " :-)" : " :-(")
    }
}
----

For method-based tags, named attributes can also bind directly to method signature arguments when the method is explicitly marked with `@Tag`:

[source,groovy]
----
import grails.gsp.Tag

class SimpleTagLib {
    @Tag
    def greeting(String name) {
        out << "Hello, ${name}!"
    }
}
----

Used as:

[source,xml]
----
<g:greeting name="Graeme" />
----

For tags with strict validation/error handling, you can keep a `Map attrs` handler and add typed overloads that delegate to it:

[source,groovy]
----
import grails.gsp.Tag

def field(Map attrs) {
    // existing validation + rendering path
}

@Tag
def field(String type, Map attrs) {
    attrs.type = type
    field(attrs)
}
----

Without `@Tag`, Grails discovers method tags only for the conventional tag signatures `def tag(Map attrs)`, `def tag(Closure body)`, and `def tag(Map attrs, Closure body)`. Zero-argument method tags and typed-parameter method tags must use `@Tag`. This prevents ordinary helper methods from being exposed as tags accidentally.

If a conventional public method should not be exposed as a tag, annotate it with `@NotATag`:

[source,groovy]
----
import grails.gsp.NotATag

class SimpleTagLib {
    @NotATag
    def helper(Map attrs) {
        // not a tag
    }
}
----

Grails applications generated with the Grails Gradle plugins preserve Java and Groovy method parameter names by default. If you compile tag libraries outside the Grails Gradle plugins, enable Java `-parameters` and Groovy `groovyOptions.parameters = true` so `@Tag` methods can bind attributes by parameter name.

As demonstrated above there is an implicit `out` variable that refers to the output `Writer` which you can use to append content to the response. Then you can reference the tag inside your GSP; no imports are necessary:

[source,xml]
----
<g:emoticon happy="true">Hi John</g:emoticon>
----

NOTE: To help IDEs like Spring Tool Suite (STS) and others autocomplete tag attributes, add Javadoc comments with `@attr` descriptions to your tag methods. Since taglibs use Groovy code it can be difficult to reliably detect all usable attributes.

For example:

[source,groovy]
----
class SimpleTagLib {

    /**
     * Renders the body with an emoticon.
     *
     * @attr happy whether to show a happy emoticon ('true') or
     * a sad emoticon ('false')
     */
    def emoticon(Map attrs, Closure body) {
       out << body() << (attrs.happy == 'true' ? " :-)" : " :-(")
    }
}
----

and any mandatory attributes should include the REQUIRED keyword, e.g.

[source,groovy]
----
class SimpleTagLib {

    /**
     * Creates a new password field.
     *
     * @attr name REQUIRED the field name
     * @attr value the field value
     */
    def passwordField(Map attrs) {
        attrs.type = "password"
        attrs.tagName = "passwordField"
        fieldImpl(out, attrs)
    }
}
----
