Skip to main content

Contacts in Joomla

10 June 2026

Many Joomla users overlook the Contacts component. They see it as a simple place to store a name and an email address, so they reach for a third-party form extension instead. That is a missed opportunity.

The Contacts component (com_contact) is two things at once. It is a structured address book for the people and places behind your website: staff, offices, departments, and partners. And it is a working contact-form engine, where every entry can carry its own email form that sends mail to the right person. No extra extension needed.

From "show our office details" to per-contact email forms, user linking, and the developer model behind it.

This article explains how Joomla Contacts really work. It covers the basics for website owners, the practical setup for administrators, and the technical details for developers. You will learn how contacts and categories fit together, how the email form works, how display inheritance is resolved, how contacts link to user accounts, and how to avoid the most common mistakes.

1. The Basics

1.1 The Two Building Blocks

The component rests on two simple concepts. Once you understand how they relate, the rest falls into place.

ConceptWhat it isDatabase table
Contact A single person or place (name, address, email, form). #__contact_details
Category A group of contacts (a com_contact category). #__categories

The relationship is easy to remember: a contact belongs to exactly one category. This is the same nested-set category tree that articles use.

1.2 How the Parts Fit Together

Here is the mental model:

Category ── Contact ──┬── Contact form  → email
                      ├── vCard         → download
                      └── Linked user   → profile + author articles
  • Contact is the data: who they are, where they are, and how to reach them.
  • Category is how you group contacts for list views and access control.
  • Form is an optional per-contact email form.
  • Linked user ties a contact to a #__users account.

A good way to keep the idea in your head: com_contact is a structured address book where every entry can also be a working contact form.

1.3 Where to Find It

In the Joomla 6 backend, you manage contacts and their categories here:

Components → Contacts → Contacts     (the people and places)
Components → Contacts → Categories   (grouping)

The front-end display is driven by menu items:

Menus → New → Contacts → (Single Contact / List / Featured / Categories)

1.4 What a Contact Actually Holds

The contact edit screen groups its fields into tabs:

TabWhat it holds
Contact Name, linked user, image, category, and the address block.
Misc Free-text "miscellaneous information" in HTML.
Display Which fields and links to show on the front end.
Form Whether the email form appears, and how it behaves.
Publishing Author, dates, and metadata.

The address block itself covers: position, address, suburb, state, country, postcode, telephone, mobile, fax, email, and webpage.

Back to top

2. Creating Contacts

2.1 Create a Category First

A contact must live in a category, so set one up before you add people:

Components → Contacts → Categories → New

  • It is an ordinary Joomla category with extension = com_contact.
  • It uses the same nested tree, the same ACL, and the same Rebuild button as article categories.

2.2 Create the Contact

Now add the contact itself:

Components → Contacts → Contacts → New

Only two fields are required:

  • Name: the person or place.
  • Category: which com_contact category it lives in.

Everything else (address, email, image, links) is optional, but it is exactly what makes the contact useful.

Beyond the standard address fields, each contact has five generic link fields. Each one is a URL plus a label:

linka / linka_name      e.g.  https://linkedin.com/...   "LinkedIn"
linkb / linkb_name      e.g.  https://github.com/...     "GitHub"
linkc ... linke

These are great for social profiles or "see also" links without creating custom fields.

You can toggle Featured (a star) on any contact. A Featured Contacts menu item then lists only those. It is the same pattern as featured articles: a curated subset shown on top of the full list.

2.5 Custom Fields Work Here Too

The Contacts component is fields-enabled, so you can extend it without code:

Components → Fields → (select "Contacts")

  • Add typed fields (text, list, calendar, media, and more) to all contacts or per category.
  • They render automatically on the contact view and can also appear on the form.

For the field-group and per-category logic, see the separate "Focus on Custom Fields" article.

Back to top

3. Displaying Contacts

3.1 A Contact Does Nothing Without a Menu Item

Like most Joomla content, a contact is just data until a menu item (or a module or plugin) renders it. There are four menu item types:

Menu item typeWhat it shows
Single Contact One contact's full detail and form.
List Contacts in a Category A table or list of one category.
Featured Contacts All contacts flagged as Featured.
List All Contact Categories The category tree as links.

3.2 The Single Contact View

The single contact view is driven by the contact's Display tab plus the menu item options. A typical layout looks like this:

[ image ]   Name
            Position
            Address block (each line toggleable)
            Telephone / Mobile / Fax / Email / Webpage
            Misc information
            Links (linka...linke)
            Contact form

Every line has a Show / Hide / Use Global setting. The global defaults live in the component Options.

3.3 The Three-level Display Inheritance

Whether a single field shows is resolved in this order, from most specific to most general:

Contact (Display tab)      Show / Hide / Use Global
   └─ Menu item options    Show / Hide / Use Global
        └─ Component Options (global default)

"Use Global" is the glue. Set a value once in Options, then override it per menu item or per contact only where you actually need to.

3.4 List and Category Views

  • The List view shows a sortable table: name, position, phone, and so on.
  • Columns, the search filter, and pagination are all menu item options.
  • The Categories view renders the tree, where each node links to its own list.

3.5 vCard Download

Each contact can offer a downloadable vCard (a .vcf file). This is the standard format that every address book imports.

allow_vcard = 1   →   "Download contact details" link on the contact view
  • Joomla ships a dedicated view for it: src/View/Contact/VcfView.php.
  • It serialises the name, position, address block, phone, email, and webpage into a .vcf file.
  • Visitors click once and the contact lands straight in their phone or mail client.

Toggle Allow vCard Download on the Display tab (or globally in Options). One field, zero extra work: a directory that exports itself.

Back to top

4. The Contact Form and Email

4.1 The Form Is the Killer Feature

Each contact can expose an email form. When a visitor submits it, Joomla sends a mail to that contact's address. You do not need a third-party form extension.

Visitor fills form  →  Joomla validates  →  email to contact  →  optional copy/reply

You turn it on from the contact's Form tab, or globally in Options.

4.2 Where the Mail Goes

The recipient is the contact's own address, stored in the email_to field. This is an important detail: the mail goes to email_to, not to the linked user's account email.

The Form tab gives you several options:

OptionEffect
Show Contact Form Master on/off switch for this contact.
Send Copy to Submitter Send the visitor a copy of their own message.
Banned Email / Subject / Text Simple spam filters (blocklists).
Session Check Require a valid session (validate_session) as an anti-bot measure.
Custom Reply Suppress Joomla's auto-reply so a plugin or integration can handle it.

4.3 The Redirect After Submit

The redirect field sets where the visitor lands after a successful submit:

  • Empty: back to the contact page with a "thank you" message.
  • Set: a custom "thank you" page, which is handy for conversion tracking.

4.4 Built-in Spam Mitigation

Contacts ship with lightweight defenses that need no CAPTCHA to be useful:

  • CSRF token: every submit calls checkToken() in ContactController::submit(). A forged or stale POST is rejected before anything else runs.
  • Banned email / subject / text: substring blocklists, set per contact.
  • Session check: rejects posts that have no live Joomla session, which kills naive bots.
  • CAPTCHA plugin: if a global CAPTCHA (for example reCAPTCHA) is set, the form uses it automatically.

The CSRF token is always on. Layer the session check and a global CAPTCHA on top, and you stop most spam without any extra extensions.

4.5 Email Cloaking

Email addresses shown on the page run through the Email Cloaking content plugin:

This email address is being protected from spambots. You need JavaScript enabled to view it.  →  obfuscated JS  →  rendered to humans, hidden from scrapers
  • The add_mailto_link setting controls whether the address becomes a clickable mailto: link.
  • Cloaking is on by default: harvesters see scrambled markup, while visitors see the real address.
Back to top

5. Categories and Access Control

5.1 Contacts Use the Shared Category System

Contact categories are ordinary Joomla categories with extension = com_contact:

#__categories  WHERE extension = 'com_contact'

That means they share the same nested tree, the same Rebuild button, and the same ACL machinery as article categories.

5.2 Why Categories Matter Here

  • A List or Categories menu item targets a category, and that becomes your directory.
  • You can organise by department, office, region, or team.
  • Permissions inherit down the tree (Create, Edit, Edit State, Delete).

For the lft and rgt nested-set details, see the "Focus on Categories" article.

5.3 Access and Language

  • The Access level on a contact controls who can view it.
  • The Language setting lets a contact appear only on its matching site language.
  • Combine the two on a multilingual site: one structure, with people filtered by language.
Back to top

6. Plugins and Integrations

6.1 Contacts Is a Small Ecosystem

Six core plugins extend com_contact:

PluginTypeWhat it does
Contact content Shows the author's contact box under an article.
Contact Creator user Auto-creates a contact when a user registers.
Contact editors-xtd Editor button to insert a link to a contact.
Contacts finder Smart Search indexer for contacts.
Contact privacy Exports and removes contact data for GDPR requests.
Contact webservices Enables the REST API routes.

6.2 Linking a Contact to a User

The user_id field ties a contact to a #__users account:

Contact.user_id  →  #__users.id

This link unlocks several features:

  • Show User Custom Fields: the user's profile fields appear on the contact page.
  • The Contact content plugin: an "About the author" box links articles back to the contact.
  • A single identity: the person's login account and their public contact entry are the same person.

6.3 Contact Creator: Automatic Profiles

The Contact Creator plugin lives at plugins/user/contactcreator:

  • On user registration, it auto-creates a linked contact.
  • It is configurable: you choose the target category, whether to autopublish, and whether to auto-fill the webpage.

It hooks into Joomla's user event:

onUserAfterSave   →   ContactCreator   →   insert #__contact_details (user_id linked)

This is a clean example of an event-driven plugin: every new member becomes a directory entry without any manual data entry.

6.4 The "About the Author" Plugin

The content plugin at plugins/content/contact lets an article display its author's contact:

Article.created_by  →  Contact.user_id  →  render contact box / link

You configure it globally (position, and whether it links or embeds). It bridges com_content and com_contact through the shared user id.

6.5 Smart Search and Privacy

  • The Finder plugin indexes contacts, so they appear in site search results.
  • The Privacy plugin makes contacts part of GDPR export and removal requests. This matters, because a contact can hold a real person's data.
Back to top

7. Under the Hood (Developer View)

7.1 One Main Table

The contacts themselves live in a single table:

#__contact_details   the contacts (people/places) + form/display params

Plus rows in the shared #__categories (with extension = com_contact), and the #__fields* tables when custom fields are used.

7.2 Key Columns in #__contact_details

The most important columns are:

id, name, alias            identity + SEF slug
catid                      category id (→ #__categories)
user_id                    linked Joomla user (→ #__users), 0 = none
con_position               job title / position
address, suburb, state,
country, postcode          the address block
telephone, mobile, fax     phone numbers
email_to                   form recipient address
webpage                    website URL
image                      photo / logo
misc                       free HTML "miscellaneous" block
linka...linke / *_name     five generic URL + label slots
default_con                the category's default contact
featured                   featured flag
sortname1/2/3              fields for custom sorting (e.g. last name)
params                     JSON: every show_* toggle + form options
metakey/metadesc/metadata  SEO + robots
published, access, language, ordering, hits, version
publish_up / publish_down  scheduling window

7.3 The MVC Layout

The component is split into an administrator side and a site side:

administrator/components/com_contact/   ← manage contacts + categories
   src/Model/ContactModel.php, ContactsModel.php
   src/Table, src/Controller, tmpl/, forms/contact.xml

components/com_contact/                  ← front-end views
   src/Model/ContactModel.php     (single contact + form submit)
   src/Model/CategoryModel.php    (list in a category)
   src/Model/FeaturedModel.php    (featured list)
   src/Model/CategoriesModel.php  (category tree)
   src/Controller/ContactController.php  (form POST handler)

plugins/...                              ← the six integrations

Note how the five site models map almost one-to-one onto the four menu item types, with the contact model also handling the form submit.

7.4 The Form Submission Flow

When a visitor submits a contact form, the request follows this path:

POST /index.php?option=com_contact&task=contact.submit&id=42
   → ContactController::submit()
   → validate (session check, banned words, CAPTCHA)
   → build + send email (Joomla Mailer)
   → optional copy to submitter
   → redirect (custom URL or back with message)

The component's own controller, not a generic form component, owns the validation and the mailing.

7.5 SEF URLs and the Router

Contact URLs are built and parsed by the component's router:

components/com_contact/src/Service/Router.php

It turns query strings into clean, human-readable paths and back again:

index.php?option=com_contact&view=contact&id=7   ↔   /contact/support/peter-martin

The router is responsible for three jobs:

  • Build: generate SEF links for contacts, categories, and featured views.
  • Parse: resolve an incoming SEF path back to the right view and id.
  • Menu resolution: prefer an existing menu item's segment over a generic path.

Because routing lives inside the component, contact links survive category moves and respect your menu structure automatically.

7.6 Web Services API (Headless)

The component ships REST routes, enabled by the webservices plugin:

api/components/com_contact/src/Controller/ContactController.php
GET  /api/index.php/v1/contact/contacts
GET  /api/index.php/v1/contact/contacts/{id}
POST /api/index.php/v1/contact/contacts        (create)

This opens the door to modern architectures:

Joomla API  →  React / Vue directory  →  custom contact rendering

The data lives in Joomla, but the delivery can live anywhere. Keep in mind that API delivery bypasses the built-in form mailer, so you handle form submissions yourself.

7.7 Programmatic Access

The same nested-set Categories API works for contacts:

use Joomla\CMS\Categories\Categories;

$categories = Categories::getInstance('Contact');
$node       = $categories->get('staff');   // by alias or id
$children   = $node->getChildren();

And the table and model classes live under these namespaces:

Joomla\Component\Contact\Administrator\Table\ContactTable
Joomla\Component\Contact\Site\Model\ContactModel

7.8 Template Overrides

Every view is overridable per template:

components/com_contact/tmpl/contact/default.php
templates/<your_template>/html/com_contact/contact/default.php   ← override

The single-contact view is split into sub-layouts (_address, _user_custom_fields, _links, and more), so you can override just the address block or just the form, instead of the whole page. The rule of thumb: override the view, not the model. Data and presentation stay separate.

7.9 At Scale

The data model is simple, but a few things bite on large directories with thousands of contacts:

ConcernWhyMitigation
List query cost Category and featured views filter and sort big result sets. Index catid, published, access, language.
User-link lookups "Articles by author" and profile joins use user_id. Index user_id (0 = none is common, so keep it indexed).
Custom-field joins #__fields_values grows per contact times per field. Limit fields shown in list views; render on demand.
Category depth Deep nested trees widen lft/rgt scans. Keep the tree shallow; Rebuild after bulk moves.

Contacts are read-heavy and write-light. Cache the views and index the filter columns, and the component scales comfortably.

Back to top

8. Common Mistakes and Pitfalls

8.1 "The Contact Form Doesn't Appear"

Work through this checklist:

  • Is Show Contact Form enabled (on the contact's Form tab, and not hidden globally)?
  • Does the contact have an email_to address?
  • Is the menu item a Single Contact? List views do not show the form.
  • Is a mis-set Use Global hiding it at a higher level?

8.2 "The Email Never Arrives"

  • Is the site mail configured, and not silently failing? Check with a tool like MailHog locally.
  • Are the banned text, subject, or email filters rejecting it?
  • Is the session check failing for a cached or anonymous post?
  • Remember the recipient is email_to, not the linked user's address. Verify that it is actually set.

8.3 Display Confusion

  • The three-level Show / Hide / Use Global inheritance trips up everyone. Check all three layers.
  • A blank single-contact page usually means everything is set to Hide.
  • Linked-user custom fields only show if both the link and "Show User Custom Fields" are on.

8.4 Privacy and Data

  • A contact can hold a real person's personal data, so include it in your privacy policy.
  • The Privacy plugin must be enabled for GDPR export and removal to cover contacts.
  • Email cloaking protects the display, but the address is still stored in the database in plain text.
Back to top

9. Best Practices

If you only remember a few things from this article, remember these:

  • Create a category before you add contacts; every contact must live in one.
  • The form recipient is email_to, not the linked user's account email.
  • Master the three-level Show / Hide / Use Global inheritance: set defaults once in Options, override only where needed.
  • Link contacts to users to unlock profiles, author boxes, and a single identity.
  • Enable the Privacy plugin so contacts are covered by GDPR export and removal.
  • Index the filter columns on large directories, and keep the category tree shallow.
Back to top

10. Quick Reference

CONTACT      Components → Contacts → Contacts → New
CATEGORY     Components → Contacts → Categories (extension=com_contact)
DISPLAY      Menus → New → Contacts → Single / List / Featured / Categories
FORM         Contact → Form tab → Show Contact Form (+ email_to)
RECIPIENT    email_to  (NOT the linked user's address)
LINK USER    Contact.user_id → #__users.id
INHERIT      Contact → Menu item → Component Options (Use Global)
FEATURED     star a contact → Featured Contacts menu item
VCARD        allow_vcard → downloadable .vcf (VcfView)
LINKS        linka...linke (+ _name labels), five slots
FIELDS       Components → Fields → Contacts (custom fields)
PLUGINS      contactcreator (onUserAfterSave), content/contact (author box), finder, privacy
SPAM         CSRF token (always) + banned words + session check + CAPTCHA
CLOAK        Email Cloaking content plugin (on by default)
ROUTER       src/Service/Router.php → SEF /contact/<cat>/<alias>
OVERRIDE     templates/<tpl>/html/com_contact/contact/default.php
INDEXES      catid, user_id, published, access, language
API          /api/index.php/v1/contact/contacts
TABLE        #__contact_details  (+ #__categories)
Back to top

11. Summary

Joomla Contacts is a structured address book and a contact-form engine in one, hiding in plain sight. Once you see it that way, you stop reaching for extra extensions for jobs the core already does well.

It gives you:

  • Structure: typed fields, an address block, five link slots, and custom fields.
  • Forms: per-contact email forms with spam mitigation, no extension needed.
  • Identity: link contacts to users, auto-create profiles, and show author boxes.
  • Display: four menu views with three-level Show / Hide inheritance.
  • Integration: a shared Categories tree, ACL, Smart Search, Privacy, and a REST API.
  • Privacy: email cloaking plus GDPR export and removal out of the box.

If you are building a staff directory, a member list, or simply want a reliable contact page that emails the right person, the Contacts component is worth a fresh look. It is the quiet, well-built address book that has been part of Joomla all along.

Back to top
Contacts in Joomla
Peter Martin
Peter Martin

Joomla specialist and Linux admin for fast, secure and scalable websites.