You could use react-slick slider.
Sample test demo in my SPFx:
You could customize the Previous Next as image instead of text.
Update:
The library supports custom HTML.
Update part2:
My test component(many test scenarios, ignore others)
import * as React from 'react';
import styles from './ReactSpFx.module.scss';
import { IReactSpFxProps } from './IReactSpFxProps';
import { escape } from '@microsoft/sp-lodash-subset';
import { SPHttpClient, SPHttpClientResponse,MSGraphClient } from '@microsoft/sp-http';
import Slider from "react-slick";
import "../../../../node_modules/slick-carousel/slick/slick.css";
import "../../../../node_modules/slick-carousel/slick/slick-theme.css";
import { any } from 'prop-types';
import { GraphFileBrowser } from '@microsoft/file-browser';
import { graph } from "@pnp/graph";
import { taxonomy, ITermStore, ITermSet, ITerms, ITermData, ITerm } from "@pnp/sp-taxonomy";
export interface IReactItem{
ID:string,
Title:string,
Address:string
Pic:{
Description:string,
Url:string
}
}
export interface IReactGetItemsState{
items:IReactItem[],
selectValue:string
}
declare global {
interface Window { _graphToken: any; }
}
const logo: any = require('../../assets/panda.jpg');
export default class ReactSpFx extends React.Component<IReactSpFxProps,IReactGetItemsState> {
public constructor(props: IReactSpFxProps) {
super(props);
window._graphToken =props.userToken;
this.state = {
items:[],
selectValue:"Radish"
};
this.next = this.next.bind(this);
this.previous = this.previous.bind(this);
graph.setup({
spfxContext: this.props.context
});
}
public getAuthenticationToken():Promise<string> {
return new Promise(resolve => {
resolve(
window._graphToken
);
});
}
private getTermsetWithChildren(termStoreName: string, termsetId: string) {
return new Promise((resolve, reject) => {
//const taxonomy = new Session(siteCollectionURL);
const store: any = taxonomy.termStores.getByName(termStoreName);
store.getTermSetById(termsetId).terms.select('Name', 'Id', 'Parent').get()
.then((data: any[]) => {
let result = [];
// build termset levels
do {
for (let index = 0; index < data.length; index++) {
let currTerm = data[index];
if (currTerm.Parent) {
let parentGuid = currTerm.Parent.Id;
insertChildInParent(result, parentGuid, currTerm, index);
index = index - 1;
} else {
data.splice(index, 1);
index = index - 1;
result.push(currTerm);
}
}
} while (data.length !== 0);
// recursive insert term in parent and delete it from start data array with index
function insertChildInParent(searchArray, parentGuid, currTerm, orgIndex) {
searchArray.forEach(parentItem => {
if (parentItem.Id == parentGuid) {
if (parentItem.children) {
parentItem.children.push(currTerm);
} else {
parentItem.children = [];
parentItem.children.push(currTerm);
}
data.splice(orgIndex, 1);
} else if (parentItem.children) {
// recursive is recursive is recursive
insertChildInParent(parentItem.children, parentGuid, currTerm, orgIndex);
}
});
}
resolve(result);
}).catch(fail => {
console.warn(fail);
reject(fail);
});
});
}
public componentDidMount() {
this.getTermsetWithChildren(
'Taxonomy_hAIlyuIrZSNizRU+uUbanA==',
'70719569-ae34-4f24-81b9-0629d68c05aa'
).then(data => {
console.log(data);
});
var reactHandler = this;
this.props.context.spHttpClient.get(`${this.props.context.pageContext.web.absoluteUrl}/_api/web/lists/getbytitle('TestList')/items?select=ID,Title,Address,Pic`,
SPHttpClient.configurations.v1) .then((response: SPHttpClientResponse) => {
response.json().then((responseJSON: any) => {
reactHandler.setState({
items: responseJSON.value.sort()
});
});
});
var userJSON={
"@odata.id": "https://graph.microsoft.com/v1.0/users/[email protected]"
};
protected slider;
next() {
this.slider.slickNext();
}
previous() {
this.slider.slickPrev();
}
handleChange = (event) => {
this.setState({selectValue:event.target.value});
};
renderPic (item) {
if (item.Pic === null) {
return <img width={150} height={150}/> //use a default image better
} else {
return <img width={150} height={150} src={item.Pic.Url} />
}
}
protected AddUserToGroup(){
}
public render(): React.ReactElement<IReactSpFxProps> {
const settings = {
dots: true,
infinite: true,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1
};
this.props.context.msGraphClientFactory
.getClient()
.then((client: MSGraphClient): void => {
// get information about the current user from the Microsoft Graph
client
.api('/me')
.get((error, response: any, rawResponse?: any) => {
let user=response.displayName;
});
});
return (
<div className={styles.reactSpFx}>
<div className={styles.container}>
Image Load
<img src={require('../../assets/panda.jpg')} alt="test" />
<div className={styles.img} title="Rencore logo">content</div>
<button className="button" onClick={this.AddUserToGroup}>
AddUserToGroup
</button>
{(this.state.items || []).map((item, index) => (
<div key={item.ID} className={(index%2==0)?styles.rowA:styles.rowB}>{item.Title}
{index%2}
{this.renderPic(item)}
{/* <div dangerouslySetInnerHTML={{ __html: item.Address.replace(/[\n\r]/g,"<br/>")}}></div> */}
</div>
))}
</div>
<select
value={this.state.selectValue}
onChange={this.handleChange}>
<option value="Orange">Orange</option>
<option value="Radish">Radish</option>
<option value="Cherry">Cherry</option>
</select>
<div>
<h2> Single Item</h2>
<Slider ref={c => (this.slider = c)} {...settings}>
<div>
<h3>1</h3>
<img width="100%" height="300" src="https://i.sstatic.net/yG5lu.png"></img>
</div>
<div>
<h3>2</h3>
<img width="100%" height="300" src="https://media.wired.com/photos/5d09594a62bcb0c9752779d9/master/w_2560%2Cc_limit/Transpo_G70_TA-518126.jpg"></img>
<div>
The SharePoint Framework (SPFx) is a page and web part model that provides full support for client-side SharePoint development, easy integration with SharePoint data, and support for open source tooling. With the SharePoint Framework, you can use modern web technologies and tools in your preferred development environment to build productive experiences and apps that are responsive and mobile-ready from day one. The SharePoint Framework works for SharePoint Online and also for on-premises (SharePoint 2016 Feature Pack 2 and SharePoint 2019).
</div>
</div>
<div>
<h3>3</h3>
<img width="100%" height="300" src="https://i.sstatic.net/yG5lu.png"></img>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
</Slider>
<br/>
<br/>
<div style={{ textAlign: "center" }}>
<button className="button" onClick={this.previous}>
Previous
</button>
<button className="button" onClick={this.next}>
Next
</button>
</div>
</div>
</div>
);
}
}
prevButtonStyles
andnextButtonStyles
as given in documentation.