The Conservatives have held on to the southeast London seat of Old Bexley and Sidcup after a by-election prompted by the death of MP James Brokenshire in October.
Mr Brokenshire, who represented the area from 2010 until his death from lung cancer, had held the seat with a majority of almost 19,000.
Thursday’s by-election, however, was tighter, with local Tory councillor Louie French gaining 11,189 votes, over Labour councillor Daniel Francis, who secured 6,711 votes.
Mr French was deputy leader of Bexley Council from 2018 to 2021, and Mr Francis is a former leader of the council’s Labour group.
After his win was announced, Mr French praised his predecessor, saying Mr Brokenshire had “made an enormous impact on everyone who lives here” and promising to “work tirelessly to build on everything he achieved”.
He told Sky News: “I’m absolutely delighted to become the first home-grown MP for our local area.
“It’s a great privilege, I’m deeply honoured to be wearing the ribbon.”
The main issues raised by residents during his campaign had been crime and policing, public transport, and problems with health services such as getting GP appointments.
The by-election turnout was significantly lower than the general election two years ago, with just 34% – 21,788 people – casting a vote.
This was down from the 46,145 votes cast in 2019 – a turnout of almost 70%.
Mr French said that it had been a “cold December night”, adding: “When we get back to the usual summer elections, we won’t have as many layers on and I think more people will come out to vote for me.”
Conservative Party chairman Oliver Dowden told Sky News the by-election outcome was a “good result for a governing party mid-term”.
“As you know, governing parties shouldn’t expect to do well mid-term,” he said. “We actually secured over 50% of the vote in Bexley, and I pay tribute to our excellent candidate and the campaign team there that secured that result.
“This idea that Labour have made some surge ahead is really for the birds. They have actually got about the same vote share as they secured under Jeremy Corbyn in 2017.
“And Keir Starmer couldn’t even be bothered to turn up to the by-election, so I’m really not terribly worried about Labour.”
Asked about Labour’s result in Old Bexley and Sidcup, the party’s national campaign co-ordinator, Shabana Mahmood, described the constituency as a “Tory stronghold of long-standing”.
“I think what I saw when I was out there campaigning myself is the incompetence of the prime minister and the litany of broken promises are catching up with him, and I think we have seen that reflected in the result,” she told Sky News.
“By any measure, and by any by-election standards, a 10.3% swing towards us is an extremely good result for the Labour Party.
“Because we know that if that result was replicated on a uniform swing across the country at a general election, that would put us within touching distance of a majority Labour government.
“So I think the prime minister should be worried because Tory campaigners in that seat will know a true blue Tory heartland like Old Bexley and Sidcup was returning a lot of dissatisfaction with the prime minister and his government.”
Standing for the Liberal Democrats was Simone Reynolds, while Jonathan Rooks was representing the Greens and Richard Tice was standing for the Reform Party.
Other candidates included Elaine Cheeseman (English Democrats), Richard Hewison (Rejoin EU), David Kurten (Heritage Party), John Poynton (UKIP), Carol Valinejad (Christian Peoples Alliance), and Mad Mike Young (Official Monster Raving Loony Party).