One other alternative, if you want to retain some of the functionality associated with heatmap, is to replace replace all values above the diagonal with NaN and then set all NaNs to white. The result will (look like) a triangular heatmap.
data = randi(100, [15, 15]);
ii = ones(size(data));
idx = tril(ii);
data(~idx) = nan;
heatmap(data, 'MissingDataColor', 'w', 'GridVisible', 'off', 'MissingDataLabel', " ")
Granted you now have an issue with an empty "missing data" label on the colorbar. You may find it preferable to set 'ColorbarVisible' to 'off', but now you have the options provided by the heatmap function.