I'm using react-beautiful-dnd
to make table rows draggable.
The dragging is working fine if I am going from top to bottom, and when I scroll the page up it gets out of position.
I have no idea why.
Also, I didn't find anything weird with css
I have no idea why this is happening and don't know how to fix this. Here is an example of my problem.
This is my code:
import update from "immutability-helper";
import * as React from "react";
import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd";
import { WithNamespaces, withNamespaces } from "react-i18next";
import { toastr } from "react-redux-toastr";
import * as HttpHelper from "../../httpHelper";
import { FormState } from "../common/ValidatedForm";
type Props = WithNamespaces & {
id: number;
displayName: string;
type: string;
language: any;
};
interface Fields {
columns: any;
}
type State = FormState<Fields> & {
isLoading: boolean,
canSave: boolean,
isSaving: boolean,
possibleTags: any,
configTagModalActive: boolean,
previewModalActive: boolean,
activeTag: any
};
const getItemStyle = (isDragging: any, draggableStyle: any) => ({
...draggableStyle,
opacity: isDragging ? 1 : 1,
boxShadow: "0px 0px 0px 1px #8b8b8b",
});
const shadowColor = "#a0a0a057";
const Column = (props: any) => {
function findindex(val: any, pt: any) {
const list = pt ? props.possibleTags : props.tags;
return list.findIndex((item: any) => val == item.name);
}
function findindexofhelptext(val: any, pt: any) {
const list = pt;
return list.findIndex((item: any) => val == item.language);
}
return (
<tr ref={props.provided.innerRef} {...props.provided.draggableProps} style={getItemStyle(props.snapshot.isDragging, props.provided.draggableProps.style)} className={"draggablerow " + (props.snapshot.isDragging ? "draggedrow" : "") } key={props.indexnr} data-id={props.index} >
<td {...props.provided.dragHandleProps} style={{width: "50px", textAlign: "center", cursor: "move"}}><i className="fa fa-bars" style={{lineHeight: "40px", fontSize: "24px"}}></i></td>
<td style={{ textAlign: "center", width: "100px" }}>
<input
type="checkbox"
className="flipswitch"
id={props.index}
checked={props.export}
onChange={props.toggleVisible}
/>
</td>
<td style={{width: "350px" }}>
<input
type="text"
name="caption"
id={props.index}
className="form-control"
value={props.caption}
onChange={props.onTextUpdate}
style={{boxShadow: "2px 2px 3px 1px" + shadowColor}}
/>
</td>
<td style={{width: "350px" }}>
<input
type="text"
name="fieldname"
id={props.index}
className="form-control"
value={props.fieldname}
onChange={props.onTextUpdate}
style={{boxShadow: "2px 2px 3px 1px" + shadowColor}}
/>
</td>
<td style={{width: "400px"}}>
<div className="tags-input" style={tagInputStyle}>
{Object.keys(props.tags).map((key, i) =>
<div key={i} className="tag" onClick={props.onConfigButtonClicked} data-id={i} data-parent={props.index}>
{props.tags[i].name} <i className="fa fa-trash" id={props.index} data-key={i} data-name={props.tags[i].name} onClick={props.onDeleteTag} style={{float: "right"}} ></i>
</div>
)}
</div>
</td>
<td style={{ textAlign: "center", width: "100px" }}>
<button onClick={() => props.onDeleteColumn(props.index)} type="button" style={{padding : "8px 16px", boxShadow: "2px 2px 2px 1px" + shadowColor }} className="btn btn-danger btn-rounded"><i className="fa fa-trash"></i></button>
</td>
</tr>
);
};
const reorder = (list: any, startIndex: any, endIndex: any) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
interface SetColumnsResponse extends HttpHelper.ResponseData { columns: any; }
class CrmConnectorColumns extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.moveColumn = this.moveColumn.bind(this);
this.state = {
isLoading: true,
isSaving: false,
canSave: false,
errorColor: "danger",
fields: { columns: [] },
deleteModalActive: false,
configTagModalActive: false,
previewModalActive: false,
activeTag: {name: "", attributes: [{name: "", value: ""}]},
possibleTags: [
{name: "PRIMARY", status: "new", helptexts: [
{language: "nl", helptext: "Dit is de primary key"},
{language: "en", helptext: "This is the primary key"}
], attributes: [], uses: 1},
{name: "SUBTITLE", status: "new", helptexts: [
{language: "nl", helptext: "Dit is de subtitel van een record"},
{language: "en", helptext: "This is The subtitle of a record"}
], attributes: [], uses: 1},
{name: "URL", status: "new", helptexts: [
{language: "nl", helptext: "De waarde wordt gezien als link."},
{language: "en", helptext: "The value becomes a link."}
], attributes: [
{name: "link", status: "new", helptexts: [
{language: "nl", helptext: "De link krijgt deze waarde. Voorbeeld waarde is \"=[naam]\". de waarde van \"[naam]\" wordt ingevuld."},
{language: "en", helptext: "The link gets this value. Example value is \"=[name]\". the value of \"[name]\" gets filled in."}
]}
], uses: undefined},
{name: "TITLE", status: "new", helptexts: [
{language: "nl", helptext: "Dit is de hoofdtitel van een record"},
{language: "en", helptext: "This is the maintitle of a record"}
], attributes: [], uses: 1},
{name: "PHONE", status: "new", helptexts: [
{language: "nl", helptext: "De waarde wordt gezien als telefoonnummer"},
{language: "en", helptext: "The value becomes a phonenumber"}
], attributes: [], uses: undefined},
{name: "BUTTON", status: "new", helptexts: [
{language: "nl", helptext: "Uiterlijk van een knop"},
{language: "en", helptext: "The value becomes a button"}
], attributes: [], uses: undefined},
{name: "EMAIL", status: "new", helptexts: [
{language: "nl", helptext: "De waarde wordt gezien als e-mail adres"},
{language: "en", helptext: "The value becomes a emailaddress"}
], attributes: [], uses: undefined},
{name: "IMAGE", status: "new", helptexts: [
{language: "nl", helptext: "De waarde wordt als afbeelding weergegeven"},
{language: "en", helptext: "The value gets displayed as image"}
], attributes: [], uses: undefined},
{name: "HTML", status: "new", helptexts: [
{language: "nl", helptext: "De waarde wordt gezien als HTML"},
{language: "en", helptext: "The value gets seen as custom HTML"}
], attributes: [
{name: "HTML code", status: "new", helptexts: [
{language: "nl", helptext: "Vul hier je custom HTML code in. De waarde tussen de [] word vervangen door de data."},
{language: "en", helptext: "Enter your custom HTML here. The value between the [] will be replaced for the value."}
]}
], uses: undefined}
]
};
this.onDragEnd = this.onDragEnd.bind(this);
}
onDragEnd(result: any) {
// dropped outside the columns table
if (!result.destination) {
return;
}
let newlist = [...this.state.fields.columns];
newlist = reorder(
newlist,
result.source.index,
result.destination.index
);
Object.keys(newlist).forEach((nr) => {
newlist[parseInt(nr, 10)].index = parseInt(nr, 10);
});
this.setState({ fields: { columns: newlist } });
this.setState({ canSave: true });
}
async componentDidMount() {
console.log("Start select columns");
const fields = await HttpHelper.getJson<Fields>(`/${this.props.type}/${this.props.id}/columns`);
this.setState(prevState => {
return update(prevState, {
fields: { $set: fields },
isLoading: { $set: false },
});
});
if (this.state.fields.columns == undefined) {
this.setState({ fields: { columns: [] } });
}
for (let i = 0; i < fields.columns.length; i++) {
fields.columns[i].index = i;
}
this.setState({ fields: { columns: fields.columns } });
const newlist = [...this.state.possibleTags];
for (const column of fields.columns) {
for (const tags of column.tags) {
const index = newlist.map((item) => item.name).indexOf(tags.name);
if (newlist[index].uses > 0) {
newlist[index].uses = 0;
}
}
}
this.setState({ possibleTags: newlist });
}
moveColumn(index: any, indexnr: any) {
const cards = this.state.fields.columns;
const sourceCard = cards.find((card: any) => card.index === index);
const sortCards = cards.filter((card: any) => card.index !== index);
sortCards.splice(indexnr, 0, sourceCard);
Object.keys(sortCards).forEach((nr) => {
sortCards[nr].index = parseInt(nr, 10);
});
this.setState({ fields: { columns: sortCards } });
this.setState({ canSave: true });
}
onDragStart = (e: any) => {
e.dataTransfer.effectAllowed = "move";
e.dataTransfer.setData("text/html", e.target.parentNode);
e.dataTransfer.setDragImage(e.target.parentNode, 20, 20);
}
ondragOver(e: any) {
e.preventDefault();
}
public render() {
const columns = this.state.fields.columns || [] ;
const { t } = this.props;
let placeholder: any;
if (columns.length < 1) {
placeholder = <tr style={{boxShadow: "0px 0px 0px 1px #8b8b8b", textAlign: "center"}} className={"draggablerow"}><td colSpan={6} >{t("placeholder")}</td></tr>;
}
return (
<form>
<div className="App">
<main>
<button onClick={this.onSubmit} className="btn btn-primary" type="submit" style={{float: "right", boxShadow: "2px 2px 3px 1px" + shadowColor}} disabled={!this.state.canSave || this.state.isSaving}>{this.state.isSaving ? <i className="fa fa-spinner fa-spin"></i> : ""} {this.props.t("update")}</button>
<button onClick={this.onPreviewButtonClicked} type="button" className="btn btn-primary" style={{float: "right", boxShadow: "2px 2px 3px 1px" + shadowColor, marginRight: "5px"}} >Preview</button><br/><br/>
<DragDropContext onDragEnd={this.onDragEnd}>
<table className="col-8 table columns" style={{tableLayout: "auto"}} >
<thead className="" style={{border: "2px solid #1b2847", background: "#1b2847", color: "white"}}>
<tr>
<th colSpan={2} style={{textAlign: "center"}}>
<button onClick={this.onAddColumn} disabled={columns.length > 14 ? true : false} type="button" style={{padding : "8px 16px", boxShadow: "2px 2px 3px 1px" + shadowColor }} className="btn btn-primary btn-rounded"><i className="fa fa-plus"></i> </button>
</th>
<th>{t("displayname")}</th>
<th>Element</th>
<th>Tags</th>
<th></th>
</tr>
</thead>
<Droppable droppableId="droppable" direction="vertical">
{(provided: any) => (
<tbody ref={provided.innerRef}>
{Object.keys(columns).map((element, key) => (
<Draggable key={"draggable" + key} draggableId={element} index={key}>
{(provided, snapshot) => (
<Column
key={"column" + key}
indexnr={key}
toggleVisible={this.toggleVisible}
onTextUpdate={this.onTextUpdate}
onDeleteColumn={this.onDeleteColumn}
onDeleteTag={this.onDeleteTag}
onAddTag={this.onAddTag}
possibleTags={this.state.possibleTags}
onConfigButtonClicked={this.onConfigButtonClicked}
onPreviewButtonClicked={this.onPreviewButtonClicked}
onClosePreview={this.onClosePreview}
provided={provided}
snapshot={snapshot}
language={this.props.language}
{...columns[key]}
/>
)}
</Draggable>
))}
{provided.placeholder}
</tbody>
)}
</Droppable>
</table>
</DragDropContext>
</main>
</div>
</form>
);
}
}
export default withNamespaces(["crmConnectorColumns", "Common"])(CrmConnectorColumns);
I hope someone can find out why my draggable get out of position when I scroll down on the page.
I'm using react-beautiful-dnd
to make table rows draggable.
The dragging is working fine if I am going from top to bottom, and when I scroll the page up it gets out of position.
I have no idea why.
Also, I didn't find anything weird with css
I have no idea why this is happening and don't know how to fix this. Here is an example of my problem.
This is my code:
import update from "immutability-helper";
import * as React from "react";
import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd";
import { WithNamespaces, withNamespaces } from "react-i18next";
import { toastr } from "react-redux-toastr";
import * as HttpHelper from "../../httpHelper";
import { FormState } from "../common/ValidatedForm";
type Props = WithNamespaces & {
id: number;
displayName: string;
type: string;
language: any;
};
interface Fields {
columns: any;
}
type State = FormState<Fields> & {
isLoading: boolean,
canSave: boolean,
isSaving: boolean,
possibleTags: any,
configTagModalActive: boolean,
previewModalActive: boolean,
activeTag: any
};
const getItemStyle = (isDragging: any, draggableStyle: any) => ({
...draggableStyle,
opacity: isDragging ? 1 : 1,
boxShadow: "0px 0px 0px 1px #8b8b8b",
});
const shadowColor = "#a0a0a057";
const Column = (props: any) => {
function findindex(val: any, pt: any) {
const list = pt ? props.possibleTags : props.tags;
return list.findIndex((item: any) => val == item.name);
}
function findindexofhelptext(val: any, pt: any) {
const list = pt;
return list.findIndex((item: any) => val == item.language);
}
return (
<tr ref={props.provided.innerRef} {...props.provided.draggableProps} style={getItemStyle(props.snapshot.isDragging, props.provided.draggableProps.style)} className={"draggablerow " + (props.snapshot.isDragging ? "draggedrow" : "") } key={props.indexnr} data-id={props.index} >
<td {...props.provided.dragHandleProps} style={{width: "50px", textAlign: "center", cursor: "move"}}><i className="fa fa-bars" style={{lineHeight: "40px", fontSize: "24px"}}></i></td>
<td style={{ textAlign: "center", width: "100px" }}>
<input
type="checkbox"
className="flipswitch"
id={props.index}
checked={props.export}
onChange={props.toggleVisible}
/>
</td>
<td style={{width: "350px" }}>
<input
type="text"
name="caption"
id={props.index}
className="form-control"
value={props.caption}
onChange={props.onTextUpdate}
style={{boxShadow: "2px 2px 3px 1px" + shadowColor}}
/>
</td>
<td style={{width: "350px" }}>
<input
type="text"
name="fieldname"
id={props.index}
className="form-control"
value={props.fieldname}
onChange={props.onTextUpdate}
style={{boxShadow: "2px 2px 3px 1px" + shadowColor}}
/>
</td>
<td style={{width: "400px"}}>
<div className="tags-input" style={tagInputStyle}>
{Object.keys(props.tags).map((key, i) =>
<div key={i} className="tag" onClick={props.onConfigButtonClicked} data-id={i} data-parent={props.index}>
{props.tags[i].name} <i className="fa fa-trash" id={props.index} data-key={i} data-name={props.tags[i].name} onClick={props.onDeleteTag} style={{float: "right"}} ></i>
</div>
)}
</div>
</td>
<td style={{ textAlign: "center", width: "100px" }}>
<button onClick={() => props.onDeleteColumn(props.index)} type="button" style={{padding : "8px 16px", boxShadow: "2px 2px 2px 1px" + shadowColor }} className="btn btn-danger btn-rounded"><i className="fa fa-trash"></i></button>
</td>
</tr>
);
};
const reorder = (list: any, startIndex: any, endIndex: any) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
interface SetColumnsResponse extends HttpHelper.ResponseData { columns: any; }
class CrmConnectorColumns extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.moveColumn = this.moveColumn.bind(this);
this.state = {
isLoading: true,
isSaving: false,
canSave: false,
errorColor: "danger",
fields: { columns: [] },
deleteModalActive: false,
configTagModalActive: false,
previewModalActive: false,
activeTag: {name: "", attributes: [{name: "", value: ""}]},
possibleTags: [
{name: "PRIMARY", status: "new", helptexts: [
{language: "nl", helptext: "Dit is de primary key"},
{language: "en", helptext: "This is the primary key"}
], attributes: [], uses: 1},
{name: "SUBTITLE", status: "new", helptexts: [
{language: "nl", helptext: "Dit is de subtitel van een record"},
{language: "en", helptext: "This is The subtitle of a record"}
], attributes: [], uses: 1},
{name: "URL", status: "new", helptexts: [
{language: "nl", helptext: "De waarde wordt gezien als link."},
{language: "en", helptext: "The value becomes a link."}
], attributes: [
{name: "link", status: "new", helptexts: [
{language: "nl", helptext: "De link krijgt deze waarde. Voorbeeld waarde is \"http://www.google.nl?search=[naam]\". de waarde van \"[naam]\" wordt ingevuld."},
{language: "en", helptext: "The link gets this value. Example value is \"http://www.google.nl?search=[name]\". the value of \"[name]\" gets filled in."}
]}
], uses: undefined},
{name: "TITLE", status: "new", helptexts: [
{language: "nl", helptext: "Dit is de hoofdtitel van een record"},
{language: "en", helptext: "This is the maintitle of a record"}
], attributes: [], uses: 1},
{name: "PHONE", status: "new", helptexts: [
{language: "nl", helptext: "De waarde wordt gezien als telefoonnummer"},
{language: "en", helptext: "The value becomes a phonenumber"}
], attributes: [], uses: undefined},
{name: "BUTTON", status: "new", helptexts: [
{language: "nl", helptext: "Uiterlijk van een knop"},
{language: "en", helptext: "The value becomes a button"}
], attributes: [], uses: undefined},
{name: "EMAIL", status: "new", helptexts: [
{language: "nl", helptext: "De waarde wordt gezien als e-mail adres"},
{language: "en", helptext: "The value becomes a emailaddress"}
], attributes: [], uses: undefined},
{name: "IMAGE", status: "new", helptexts: [
{language: "nl", helptext: "De waarde wordt als afbeelding weergegeven"},
{language: "en", helptext: "The value gets displayed as image"}
], attributes: [], uses: undefined},
{name: "HTML", status: "new", helptexts: [
{language: "nl", helptext: "De waarde wordt gezien als HTML"},
{language: "en", helptext: "The value gets seen as custom HTML"}
], attributes: [
{name: "HTML code", status: "new", helptexts: [
{language: "nl", helptext: "Vul hier je custom HTML code in. De waarde tussen de [] word vervangen door de data."},
{language: "en", helptext: "Enter your custom HTML here. The value between the [] will be replaced for the value."}
]}
], uses: undefined}
]
};
this.onDragEnd = this.onDragEnd.bind(this);
}
onDragEnd(result: any) {
// dropped outside the columns table
if (!result.destination) {
return;
}
let newlist = [...this.state.fields.columns];
newlist = reorder(
newlist,
result.source.index,
result.destination.index
);
Object.keys(newlist).forEach((nr) => {
newlist[parseInt(nr, 10)].index = parseInt(nr, 10);
});
this.setState({ fields: { columns: newlist } });
this.setState({ canSave: true });
}
async componentDidMount() {
console.log("Start select columns");
const fields = await HttpHelper.getJson<Fields>(`/${this.props.type}/${this.props.id}/columns`);
this.setState(prevState => {
return update(prevState, {
fields: { $set: fields },
isLoading: { $set: false },
});
});
if (this.state.fields.columns == undefined) {
this.setState({ fields: { columns: [] } });
}
for (let i = 0; i < fields.columns.length; i++) {
fields.columns[i].index = i;
}
this.setState({ fields: { columns: fields.columns } });
const newlist = [...this.state.possibleTags];
for (const column of fields.columns) {
for (const tags of column.tags) {
const index = newlist.map((item) => item.name).indexOf(tags.name);
if (newlist[index].uses > 0) {
newlist[index].uses = 0;
}
}
}
this.setState({ possibleTags: newlist });
}
moveColumn(index: any, indexnr: any) {
const cards = this.state.fields.columns;
const sourceCard = cards.find((card: any) => card.index === index);
const sortCards = cards.filter((card: any) => card.index !== index);
sortCards.splice(indexnr, 0, sourceCard);
Object.keys(sortCards).forEach((nr) => {
sortCards[nr].index = parseInt(nr, 10);
});
this.setState({ fields: { columns: sortCards } });
this.setState({ canSave: true });
}
onDragStart = (e: any) => {
e.dataTransfer.effectAllowed = "move";
e.dataTransfer.setData("text/html", e.target.parentNode);
e.dataTransfer.setDragImage(e.target.parentNode, 20, 20);
}
ondragOver(e: any) {
e.preventDefault();
}
public render() {
const columns = this.state.fields.columns || [] ;
const { t } = this.props;
let placeholder: any;
if (columns.length < 1) {
placeholder = <tr style={{boxShadow: "0px 0px 0px 1px #8b8b8b", textAlign: "center"}} className={"draggablerow"}><td colSpan={6} >{t("placeholder")}</td></tr>;
}
return (
<form>
<div className="App">
<main>
<button onClick={this.onSubmit} className="btn btn-primary" type="submit" style={{float: "right", boxShadow: "2px 2px 3px 1px" + shadowColor}} disabled={!this.state.canSave || this.state.isSaving}>{this.state.isSaving ? <i className="fa fa-spinner fa-spin"></i> : ""} {this.props.t("update")}</button>
<button onClick={this.onPreviewButtonClicked} type="button" className="btn btn-primary" style={{float: "right", boxShadow: "2px 2px 3px 1px" + shadowColor, marginRight: "5px"}} >Preview</button><br/><br/>
<DragDropContext onDragEnd={this.onDragEnd}>
<table className="col-8 table columns" style={{tableLayout: "auto"}} >
<thead className="" style={{border: "2px solid #1b2847", background: "#1b2847", color: "white"}}>
<tr>
<th colSpan={2} style={{textAlign: "center"}}>
<button onClick={this.onAddColumn} disabled={columns.length > 14 ? true : false} type="button" style={{padding : "8px 16px", boxShadow: "2px 2px 3px 1px" + shadowColor }} className="btn btn-primary btn-rounded"><i className="fa fa-plus"></i> </button>
</th>
<th>{t("displayname")}</th>
<th>Element</th>
<th>Tags</th>
<th></th>
</tr>
</thead>
<Droppable droppableId="droppable" direction="vertical">
{(provided: any) => (
<tbody ref={provided.innerRef}>
{Object.keys(columns).map((element, key) => (
<Draggable key={"draggable" + key} draggableId={element} index={key}>
{(provided, snapshot) => (
<Column
key={"column" + key}
indexnr={key}
toggleVisible={this.toggleVisible}
onTextUpdate={this.onTextUpdate}
onDeleteColumn={this.onDeleteColumn}
onDeleteTag={this.onDeleteTag}
onAddTag={this.onAddTag}
possibleTags={this.state.possibleTags}
onConfigButtonClicked={this.onConfigButtonClicked}
onPreviewButtonClicked={this.onPreviewButtonClicked}
onClosePreview={this.onClosePreview}
provided={provided}
snapshot={snapshot}
language={this.props.language}
{...columns[key]}
/>
)}
</Draggable>
))}
{provided.placeholder}
</tbody>
)}
</Droppable>
</table>
</DragDropContext>
</main>
</div>
</form>
);
}
}
export default withNamespaces(["crmConnectorColumns", "Common"])(CrmConnectorColumns);
I hope someone can find out why my draggable get out of position when I scroll down on the page.
Share Improve this question edited Dec 3, 2019 at 15:55 Sarvesh Mahajan 9247 silver badges18 bronze badges asked Mar 29, 2019 at 14:42 user10960236user10960236 8- 2 Can you add an example in codesandbox with static data? I tried adding an example but the code has missing files imported. – Special Character Commented Apr 2, 2019 at 23:44
- 12 I created an extremely basic example with the core of your code here: codesandbox.io/s/my64446wl9 I didn't see the same results that you did, so I am willing to bet it is in the styles being overridden somewhere. – Special Character Commented Apr 2, 2019 at 23:59
- Different browser versions? Try it also in incognito mode if you are getting the same results (sometimes extensions can interfere with the page) – bsekula Commented Apr 4, 2019 at 20:43
- 1 It could be that your draggable elements have an overflow scoll on them. Maybe try setting overflow-y: hidden on the draggable elements – Jake Commented Apr 4, 2019 at 21:20
- So onscroll some styles being overridden? – Webdeveloper_Jelle Commented Apr 5, 2019 at 9:46
4 Answers
Reset to default 2Perhaps it's too late for the answer, but for someone, it can be helpful.
If you look closer, you'll see the offset when you scroll and this is the reason for broken styles.
For a solution, you should think about the scroll container, if you append scroll to HTMLElement, not Window, you need to check this example.
This issue related to react-beautiful-dnd
itself and the updated version will fix that.
I have run in to the same problem. The issue for me was that droppable(list) was inside, for example, main container which was scrollable (i.e. overflow: scroll).
I resolved the issue by converting the droppable into scrollable instead of main container
Example that had an issue
.main {
background: #eee;
padding: 3rem;
height: 200px;
overflow-y: scroll;
}
.droppable {
padding: 1rem;
background: #aaa;
}
.draggable {
margin: 0.5rem 0;
padding: 1rem;
background: #ccc;
}
<div class="main">
<div class="droppable">
<div class="draggable">
<span class="text"> item</span>
</div>
<div class="draggable">
<span class="text"> item</span>
</div>
<div class="draggable">
<span class="text"> item</span>
</div>
</div>
</div>
Example with issue resolved
.main {
background: #eee;
padding: 3rem;
height: 200px;
}
.droppable {
padding: 1rem;
background: #aaa;
height: 180px;
overflow-y: scroll;
}
.draggable {
margin: 0.5rem 0;
padding: 1rem;
background: #ccc;
}
<div class="main">
<div class="droppable">
<div class="draggable">
<span class="text"> item</span>
</div>
<div class="draggable">
<span class="text"> item</span>
</div>
<div class="draggable">
<span class="text"> item</span>
</div>
</div>
</div>
Changes were made in just CSS to make droppable container shorter than the main container and added overvlow-y:scroll
to the droppable
I have also faced the same issue.
The only work around I found is
*Fixing Height of the item in case of vertical drag. *Fixing Width of the item in case of horizontal drag.
Also one More thing to mention set the display property of the item dragged to block.
I had this exact issue when my Draggables
was inside a parent using transform
. They addressed it here in the docs: https://github.com/atlassian/react-beautiful-dnd/blob/master/docs/guides/reparenting.md
Basically what you need to do is render the draggable component in a portal, which they have already built in. Here is an example from my code, notice "renderClone", which renders the dragged item:
<DragDropContext onDragEnd={handleDragEnd}>
<Droppable
droppableId={"droppable-1"}
renderClone={renderDraggedCondition}
>
{(provider) => (
<DroppableContainer
ref={provider.innerRef}
{...provider.droppableProps}
>
{renderedConditions}
{provider.placeholder}
</DroppableContainer>
)}
</Droppable>
</DragDropContext>