Skip to content

Instantly share code, notes, and snippets.

@beata
Last active August 15, 2025 04:50
Show Gist options
  • Select an option

  • Save beata/9b015a272024a96004915c49f63edc7c to your computer and use it in GitHub Desktop.

Select an option

Save beata/9b015a272024a96004915c49f63edc7c to your computer and use it in GitHub Desktop.
Obsidian - filterable datacard list
```dataviewjs
const pageTag = '#cosmetics'
const brandProperty = 'brand' // for the primary dropdown
const typeProperty = 'type' // for the secondary dropdown
const imageProperty = 'cover'
// End of Configurable Parameters
const buildDropdown = (name, optionSet) => {
const select = dv.el('select', '', { cls: `select--${name}` })
select.innerHTML = ['', ...([...optionSet].sort())].map((option, index) => `<option value="${option}">${index === 0 ? name : option}</option>`).join('')
return select
}
const buildList = (selectedBrand, selectedType) => {
const conds = ['!hidden'];
if (selectedBrand) {
conds.push(`${brandProperty} = "${selectedBrand}"`)
}
if (selectedType) {
conds.push(`contains(${typeProperty}, "${selectedType}")`)
}
const condsString = conds.length ? ` WHERE ${conds.join(' AND ')}` : ''
return dv.paragraph(`
\`\`\`datacards
TABLE cover FROM ${pageTag} ${condsString} SORT ${typeProperty}, name
// Settings
imageProperty: ${imageProperty}
preset: portrait
columns: 4
fontSize: small
truncateText: true
enableClickableCards: true
mobilePreset: portrait
mobileColumns: 1
mobileScrollableProperties: true
\`\`\`
`)
}
const brandSet = new Set()
const typeSet = new Set()
let selectedBrand = ''
let selectedType = ''
// Collect dropdown options from pages
dv.pages(pageTag).where(p => !p.hidden).forEach(p => {
brandSet.add(p.brand)
if (p.type) {
(Array.isArray(p.type) ? p.type : [p.type])
.forEach(type => typeSet.add(type))
}
})
// Build DOM Elements
const filterBox = dv.el('div', '')
filterBox.style = 'display: flex; flex-direciton: row; justify-content: flex-end; gap: 8px'
filterBox.append(buildDropdown('Brand', brandSet))
filterBox.append(buildDropdown('Type', typeSet))
const listBox = dv.el('div', '')
listBox.append(buildList(selectedBrand, selectedType))
dv.container.append(filterBox)
dv.container.append(listBox)
// Add Event Listener
filterBox.addEventListener('change', function(event) {
if (event.srcElement.classList.contains('select--Brand')) {
selectedBrand = event.target.value
selectedType = '';
if (event.srcElement.nextSibling) {
event.srcElement.nextSibling.value = selectedType;
}
} else if (event.srcElement.classList.contains('select--Type')) {
selectedType = event.target.value
}
listBox.innerHTML = '';
listBox.append(buildList(selectedBrand, selectedType))
});
```
---
tags:
- cosmetics
name: Makeup by Mario ETHEREAL EYES EYESHADOW PALETTE - MOONLIGHT
cover: https://www.makeupbymario.com/cdn/shop/files/MBM_EE2_PACKSHOT_ALT_MBCOLOR_06_MBM.jpg?v=1727801911&width=2480
link: https://www.makeupbymario.com/products/ethereal-eyes-eyeshadow-palette-moonlight-copy?variant=41785633865793
brand: Makeup by Mario
area: eye
type:
- eyeshadow palette
---
`= "![|200](" + this.cover+ ")"`
@beata
Copy link
Author

beata commented Aug 15, 2025

Example

Requirements

Usage Instructions

  • index-dataviewjs
    This is the DataviewJS snippet for displaying a card list.
    Paste it into any page where you want the card list to appear.

  • page-meta-template
    This is the template for individual card items.
    Each page created with this template will serve as a card entry that the list can query.

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