Contacts Pane
The contacts pane renders vCard data — individual contacts and address books.
What It Renders
vcard:Individual— Single contactvcard:AddressBook— Collection of contactsvcard:Group— Contact groups
Features
- Contact card display
- Photo/avatar support
- Multiple phone/email
- Address formatting
- Organization info
- Social links
- Add/edit contacts
- Import/export vCards
Screenshot
┌─────────────────────────────────────────────────┐
│ ┌────┐ │
│ │ 👤 │ Alice Smith │
│ └────┘ Software Engineer at Acme Corp │
├─────────────────────────────────────────────────┤
│ 📧 alice@example.org │
│ 📱 +1 555-123-4567 │
│ 🏠 123 Main St, City, Country │
│ │
│ 🔗 @alice@mastodon.social │
│ 🌐 https://alice.example │
├─────────────────────────────────────────────────┤
│ [Edit] [Share] [Delete] │
└─────────────────────────────────────────────────┘
RDF Structure
Individual Contact
@prefix vcard: <http://www.w3.org/2006/vcard/ns#> .
<#me>
a vcard:Individual ;
vcard:fn "Alice Smith" ;
vcard:hasName [
vcard:given-name "Alice" ;
vcard:family-name "Smith"
] ;
vcard:hasEmail <mailto:alice@example.org> ;
vcard:hasTelephone [
a vcard:Cell ;
vcard:value <tel:+1-555-123-4567>
] ;
vcard:hasAddress [
vcard:street-address "123 Main St" ;
vcard:locality "City" ;
vcard:country-name "Country"
] ;
vcard:hasPhoto <photo.jpg> ;
vcard:organization-name "Acme Corp" ;
vcard:role "Software Engineer" ;
vcard:url <https://alice.example> .
Address Book
@prefix vcard: <http://www.w3.org/2006/vcard/ns#> .
<#addressbook>
a vcard:AddressBook ;
vcard:fn "My Contacts" ;
vcard:hasMember
<alice.ttl#me>,
<bob.ttl#me>,
<carol.ttl#me> .
Usage
// Navigate to a contact
panes.runDataBrowser(document, sym('https://alice.example/contacts/alice.ttl#me'))
// Get the pane directly
const contactsPane = paneRegistry.byName('contacts')
Creating Contacts
Programmatically
import { store, sym, lit, st } from 'solid-logic'
const VCARD = Namespace('http://www.w3.org/2006/vcard/ns#')
const contact = sym('https://alice.example/contacts/bob.ttl#me')
const doc = contact.doc()
// Create the contact
const statements = [
st(contact, RDF('type'), VCARD('Individual'), doc),
st(contact, VCARD('fn'), lit('Bob Jones'), doc),
st(contact, VCARD('hasEmail'), sym('mailto:bob@example.org'), doc),
]
await store.updater.update([], statements)
Via UI
The contacts pane provides an "Add Contact" form:
- Navigate to an address book
- Click "Add Contact"
- Fill in the form
- Click "Save"
Address Book Operations
List Contacts
const addressBook = sym('https://alice.example/contacts/index.ttl#addressbook')
await store.fetcher.load(addressBook)
const contacts = store.each(addressBook, VCARD('hasMember'), null, null)
for (const contact of contacts) {
await store.fetcher.load(contact.doc())
const name = store.any(contact, VCARD('fn'), null, null)
console.log(name?.value)
}
Add to Address Book
const newContact = sym('https://alice.example/contacts/new.ttl#me')
await store.updater.update(
[],
[st(addressBook, VCARD('hasMember'), newContact, addressBook.doc())]
)
vCard Import/Export
Export to vCard
// The pane provides export functionality
// Export format: .vcf file
Example vCard output:
BEGIN:VCARD
VERSION:4.0
FN:Alice Smith
EMAIL:alice@example.org
TEL:+1-555-123-4567
END:VCARD
Import from vCard
The pane can import .vcf files:
- Click "Import"
- Select .vcf file
- Review contacts
- Confirm import
Type Index Integration
Contacts are typically registered in the Type Index:
# In private type index
<#contacts>
a solid:TypeRegistration ;
solid:forClass vcard:AddressBook ;
solid:instance </contacts/index.ttl#addressbook> .
Finding Address Books
import { typeIndex } from 'solid-logic'
const addressBooks = await typeIndex.findByType(VCARD('AddressBook').uri)
// Returns array of address book URIs
Groups
Organize contacts into groups:
<#family>
a vcard:Group ;
vcard:fn "Family" ;
vcard:hasMember
<mom.ttl#me>,
<dad.ttl#me>,
<sister.ttl#me> .
Photos
Contact photos can be:
- Linked:
vcard:hasPhoto <photo.jpg> - Embedded: Base64 in the RDF (not recommended)
// Get photo URL
const photo = store.any(contact, VCARD('hasPhoto'), null, null)
if (photo) {
const img = document.createElement('img')
img.src = photo.uri
}
Customization
Custom Fields
Add custom properties using vcard extensions:
<#me>
a vcard:Individual ;
vcard:fn "Alice" ;
# Custom field
ex:mastodon "@alice@mastodon.social" .
Styling
Override default styles:
.contact-card {
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.contact-card .avatar {
width: 80px;
height: 80px;
border-radius: 50%;
}
Source
See Also
- vCard Ontology — W3C specification
- Type Index — finding address books