Darren Sammy’s side successfully chased down a target of 123 with just two balls to spare for a third consecutive Group One victory, becoming the second team to qualify for the last four after New Zealand.
It was South Africa’s second defeat of the tournament and means England can secure a berth in the semis at their expense with a win against Sri Lanka on Saturday.
The Windies rode on a gritty 44 from Marlon Samuels to prevail in a tense finish.
They had earlier restricted South Africa to 122 for eight after Sammy opted to field first.
It looked like the Windies would canter home but Imran Tahir grabbed two wickets in the 17th over and the Caribbean side ended up going into the final over requiring nine to win.
Carlos Brathwaite hit a massive six before precocious fast bowler Kagiso Rabada bowled a wide. Brathwaite then grabbed a quick run before Denesh Ramdin carried the Windies over the line with a single.
Samuels’ 32-run partnership for the third wicket with Johnson Charles (32) set up the chase only for the team to lose their way in the middle overs.
Andre Fletcher made 11 while Chris Gayle surprisingly shone with the ball rather than the bat.
The big-hitting left hander smashed a four off his first ball but was clean bowled by Rabada off his second.
Gayle had earlier claimed two wickets as South Africa suffered from lack of partnerships in a crucial game for their survival in the tournament.
Left-hander Quinton de Kock top-scored for the Proteas with 47 while David Wiese, batting at number seven, notched 28.
Hashim Amla was run out for one on just the third ball of the innings.
Captain Faf du Plessis came in and didn’t last long, scoring nine off seven balls before being caught by Sulieman Benn off paceman Andre Russell.
It quickly got worse for the Proteas when Gayle, who has barely turned his arm over in recent years, grabbed the wicket of Rilee Rossouw.
Rossouw’s dismissal, which the dreadlocked Gayle celebrated with a little jig, left South Africa reeling on 20 for three after three overs.
South Africa needed AB de Villiers to put a big score on the board but the classy stroke-player could only manage 10 before being cleaned up by Dwayne Bravo.
David Miller then came in but lasted only four balls, bowled by Gayle. Chris Morris made 16.