AEM Dialog Components #2: Textarea - Input Testo Multi-Riga
AEM Dialog Components #2: Textarea
Cos'è un Textarea?
Il Textarea è un componente Granite UI che permette agli autori di inserire testo su più righe nelle dialog dei componenti AEM.
Differenza con Textfield:
- Textfield → Una singola riga
- Textarea → Più righe, con a capo
Casi d'uso comuni:
- Descrizioni e abstract
- Note e commenti
- Metadata e alt text
- Code snippets semplici
- Disclaimer e note legali
Configurazione Base
XML Dialog Minimo
<description
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Description"
name="./description"/>Proprietà essenziali:
sling:resourceType- Sempregranite/ui/components/coral/foundation/form/textareafieldLabel- Etichetta visibile all'autorename- Percorso JCR dove salvare il valore (usa sempre./)
Proprietà Principali
1. Required (Campo Obbligatorio)
<description
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Description"
name="./description"
required="{Boolean}true"/>2. Rows (Altezza in Righe)
<description
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Description"
name="./description"
rows="{Long}5"/>Default: 2 righe
Best practice:
- 3-5 righe per descrizioni brevi
- 8-12 righe per testo lungo
- 15+ righe per code o contenuti estesi
3. Maxlength (Lunghezza Massima)
<metaDescription
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Meta Description"
name="./metaDescription"
maxlength="{Long}160"
rows="{Long}3"
fieldDescription="Max 160 characters for SEO"/>Importante: Come textfield, usa {Long} per il type hint!
4. EmptyText (Placeholder)
<notes
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Internal Notes"
name="./notes"
emptyText="Add notes for editors..."
rows="{Long}4"/>5. Resize (Ridimensionamento)
<content
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Content"
name="./content"
resize="vertical"
rows="{Long}8"/>Valori:
vertical- Ridimensionabile verticalmente (default)both- Ridimensionabile verticalmente e orizzontalmentenone- Dimensione fissa
Esempi Pratici
Esempio 1: Meta Description (SEO)
<metaDescription
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Meta Description"
name="./metaDescription"
fieldDescription="SEO description (max 160 chars)"
required="{Boolean}true"
maxlength="{Long}160"
rows="{Long}3"
emptyText="Enter a concise description for search engines..."/>Use case: Ottimizzazione SEO delle pagine.
Esempio 2: Alt Text per Immagini
<altText
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Alt Text"
name="./altText"
fieldDescription="Describe the image for accessibility"
required="{Boolean}true"
maxlength="{Long}125"
rows="{Long}2"
emptyText="Describe what is shown in the image"/>Use case: Accessibilità e SEO per le immagini.
Esempio 3: Note Interne per Editori
<editorNotes
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Editor Notes"
name="./editorNotes"
fieldDescription="Internal notes (not displayed on the site)"
rows="{Long}5"
emptyText="Add notes for other editors..."/>Use case: Workflow e comunicazione tra autori.
Esempio 4: Descrizione Prodotto
<productDescription
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Product Description"
name="./productDescription"
required="{Boolean}true"
rows="{Long}8"
maxlength="{Long}500"
emptyText="Enter a detailed product description..."
resize="vertical"/>Use case: E-commerce, schede prodotto.
Esempio 5: Codice Embed (Script, iframe)
<embedCode
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Embed Code"
name="./embedCode"
fieldDescription="Paste third-party embed code (YouTube, Twitter, etc.)"
rows="{Long}10"
resize="vertical"
emptyText="<iframe src='...'></iframe>"/>Use case: Integrazione contenuti esterni (video, social, mappe).
Dialog Completa con Textarea
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
xmlns:granite="http://www.adobe.com/jcr/granite/1.0"
xmlns:cq="http://www.day.com/jcr/cq/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0"
xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="nt:unstructured"
jcr:title="Content Card"
sling:resourceType="cq/gui/components/authoring/dialog">
<content
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<tabs
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/tabs">
<items jcr:primaryType="nt:unstructured">
<!-- Content Tab -->
<content
jcr:primaryType="nt:unstructured"
jcr:title="Content"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<!-- Title (Textfield) -->
<title
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
fieldLabel="Title"
name="./title"
required="{Boolean}true"/>
<!-- Description (Textarea) -->
<description
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Description"
name="./description"
rows="{Long}5"
maxlength="{Long}300"
emptyText="Enter card description..."/>
</items>
</content>
<!-- SEO Tab -->
<seo
jcr:primaryType="nt:unstructured"
jcr:title="SEO"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<!-- Meta Description -->
<metaDescription
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Meta Description"
name="./metaDescription"
fieldDescription="SEO description (max 160 chars)"
maxlength="{Long}160"
rows="{Long}3"/>
<!-- Alt Text -->
<altText
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Image Alt Text"
name="./altText"
maxlength="{Long}125"
rows="{Long}2"/>
</items>
</seo>
</items>
</tabs>
</items>
</content>
</jcr:root>Uso in HTL
Lettura Valore Semplice
<div class="card-description">
${properties.description}
</div>Importante: Il testo avrà gli "a capo" (\n) che HTML ignora. Per preservarli:
<div class="card-description" style="white-space: pre-line;">
${properties.description}
</div>Oppure converti \n in <br>:
<div class="card-description">
${properties.description }
</div>Con Fallback
<div data-sly-test="${properties.description}" class="description">
${properties.description}
</div>
<!-- Oppure con operatore ternario -->
<div class="description">
${properties.description || 'No description available'}
</div>Tronca Testo con CSS
<div class="description truncate-3-lines">
${properties.description}
</div>CSS:
.truncate-3-lines {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}Con Sling Model
@Model(adaptables = Resource.class)
public class ContentCardModel {
@ValueMapValue
private String title;
@ValueMapValue
private String description;
@ValueMapValue
private String metaDescription;
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
/**
* Descrizione troncata a N caratteri per preview
*/
public String getShortDescription(int maxLength) {
if (description == null || description.length() <= maxLength) {
return description;
}
return description.substring(0, maxLength) + "...";
}
/**
* Meta description con fallback su description
*/
public String getMetaDescription() {
if (metaDescription != null && !metaDescription.isEmpty()) {
return metaDescription;
}
// Fallback: usa primi 160 caratteri della description
return getShortDescription(160);
}
/**
* Converte \n in <br> per HTML
*/
public String getDescriptionAsHtml() {
if (description == null) {
return "";
}
return description.replace("\n", "<br>");
}
public boolean hasDescription() {
return description != null && !description.isEmpty();
}
}HTL con Model:
<div data-sly-use.model="com.mysite.models.ContentCardModel" class="card">
<h3 class="card-title">${model.title}</h3>
<!-- Descrizione completa -->
<div data-sly-test="${model.hasDescription}" class="card-description">
${model.description}
</div>
<!-- Oppure descrizione troncata -->
<div class="card-preview">
${model.getShortDescription(150)}
</div>
<!-- Meta tag per SEO (in <head>) -->
<meta name="description" content="${model.metaDescription}"/>
</div>Textarea vs RichText Editor
Quando Usare Textarea
✅ Usa Textarea quando:
- Testo semplice senza formattazione
- Limiti di lunghezza stretti (es. meta description)
- Performance è importante
- Non serve bold, italic, link, etc.
- Alt text, note, metadata
Quando Usare RichText Editor
✅ Usa RichText quando:
- Serve formattazione (bold, italic, lists)
- Serve inserire link
- Contenuto editoriale lungo
- Autori hanno bisogno di flessibilità
Regola pratica: Se l'autore non ha bisogno di formattare, usa Textarea!
Proprietà Avanzate
1. autofocus
<description
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Description"
name="./description"
autofocus="{Boolean}true"/>Focus automatico all'apertura della dialog.
2. disabled e readOnly
<!-- Disabled -->
<generatedText
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Auto-Generated Text"
name="./generatedText"
disabled="{Boolean}true"
rows="{Long}4"/>
<!-- ReadOnly -->
<originalText
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Original Text"
name="./originalText"
readOnly="{Boolean}true"
rows="{Long}6"/>3. granite:class
<customTextarea
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Custom Textarea"
name="./customTextarea"
granite:class="monospace-font"
rows="{Long}10"/>Aggiungi CSS custom (es. monospace per codice).
Problemi Comuni
❌ Problema 1: A capo non visualizzati
<!-- SBAGLIATO - HTML ignora \n -->
<div>${properties.description}</div>
<!-- CORRETTO - Preserva a capo -->
<div style="white-space: pre-line;">
${properties.description}
</div>
<!-- OPPURE converti \n in <br> nel Sling Model -->
<div>${model.descriptionAsHtml }</div>❌ Problema 2: Maxlength ignorato
<!-- SBAGLIATO -->
<description maxlength="160"/>
<!-- CORRETTO -->
<description maxlength="{Long}160"/>Usa sempre {Long} per numeri.
❌ Problema 3: Textarea troppo piccola
<!-- SBAGLIATO - default 2 righe, troppo piccolo -->
<description
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
name="./description"/>
<!-- CORRETTO - imposta rows appropriate -->
<description
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
name="./description"
rows="{Long}5"/>❌ Problema 4: Testo troncato visivamente
Se il testo appare troncato nel component ma nel JCR è completo:
Causa: CSS che limita l'altezza del container
Soluzione: Verifica CSS e aggiungi overflow: auto o white-space: pre-line
Best Practices
- ✅ Rows appropriate: 3-5 per descrizioni, 8-12 per testo lungo
- ✅ Maxlength per SEO: 160 per meta description, 125 per alt text
- ✅ EmptyText esplicativo: Dai esempi chiari
- ✅ FieldDescription: Spiega limiti e uso
- ✅ Resize vertical: Permetti ridimensionamento per testi lunghi
- ✅ Preserva a capo in HTL: Usa
white-space: pre-lineo converti in<br> - ✅ Fallback su RTE: Se serve formattazione, passa a RichText
- ✅ Validation in Sling Model: Controlla lunghezza e contenuto lato server
Quando NON Usare Textarea
❌ Non usare textarea quando:
- Serve una singola riga → Usa Textfield
- Serve formattazione (bold, link) → Usa RichText Editor
- Serve codice complesso → Usa Code Editor (custom)
- Serve selezione da lista → Usa Select o Radio
Prossima Lezione
Nella prossima lezione vedremo il componente Checkbox per selezioni boolean.
Risorse:
Guida #2 della serie AEM Dialog Components - ← Lezione precedente | Prossima lezione →