I am making a budget tracking app that takes in your transaction history. In order to classify transactions, you can create Filters (eg Filter "fast food" = ContainsText("Mcdonalds") || ...)

Creating filters to cover absolutely every transaction would be cumbersome though, so I'm also adding a tagging system that allows you to say 'this transaction should be considered to be in this filter', but also, in case of false-positives, I'd like you to be able to tag a transaction as not being in a filter.

As such you have 3 states for a transaction and a filter: untagged, tagged as IN, tagged as NOT IN.

I want tagging to be a quick and easy process (one click, and as many filters showing as possible, aka, limited space per filter). So I was thinking a checked list box side panel next to the transaction grid, however with an added "cross" state, so that: unchecked = untagged, checked = tagged in, crossed = tagged not in,

Everything is untagged by default, and tagging IN will be far more common than tagging NOT IN or untagging, so I was thinking having the checkbox cycle in the order above would be perfect.

Note that I will likely need the indeterminate state as well, for when they have multiple transactions selected.

I'm not asking how to achieve the above. I'm asking: Is this a good idea? Is it a bad idea? Is there a better idea?

  • 2
    Hi matt, it depends on your audience. Personally, I find it odd that a tag has three states. Either you tag something as "Fast Food" or the tag is not active. How would you visualize a "NOT IN" tag?
    – Nash
    Mar 16, 2021 at 8:26
  • Can you explain what is the functional difference between "untagged" and "tagged in"? I can't quite grasp it
    – musefan
    Mar 16, 2021 at 16:01
  • At the moment, the first pass is to create filters to automatically categorise transactions. a transaction can be 'in' more than one filter/category. at the moment these filters are never 'baked' into the transactions. So if you change them, the transactions in them can change too. In the same vein, when 'tagging' a transaction, you aren't really adding data to the transaction (conceptually), you are adding data to the filter: eg: filter A = ContainsText("Mcdonalds") || IsSpecificTransaction(IdOfTaggedTransaction)
    – matt
    Mar 18, 2021 at 3:57
  • In my actual implementation atm, tag status is stored on the transaction, but that's just a technicality. So tagging gives you the ability to explicitly state that a transaction is 'in' a filter - regardless of whether or not it passes the actual filter expression. In the same way, you may wish to fix up false-positives and explicitly mark a transaction as NOT being 'in' a filter - even if it passes the filter expression.
    – matt
    Mar 18, 2021 at 4:01
  • So the three states are: -In (checked) -Not In (crossed) -In if passes filter expression (Unchecked) (yeah filters are sort of doubling as a filter and a category right now)
    – matt
    Mar 18, 2021 at 4:03

1 Answer 1


like Nash said, it depends on your audience. In my opinion you only should have 2 states: [unchecked = untagged, checked = tagged in] it will be direct and simpler.

In other hand Having 3 different states at same time, gives you other possibilities to search for "tagged not in". If you differentiate them well maybe can result, but only with user testing you can achieve the better result.

The better way is doing a A/B Test(you can do that with your close contacts, friends and family to have a fast input of how it will works or not).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.