captivationsoftware / react-sticky Goto Github PK
View Code? Open in Web Editor NEW<Sticky /> component for awesome React apps
License: MIT License
<Sticky /> component for awesome React apps
License: MIT License
When component mounts, div element does not have className passed as props, it happens only after first tick. Because of that, sticky block changes after page load.
As a solution, I am setting className: this.props.className in getInitialState()
<Sticky>
component are switched to position: fixed
<Sticky>
, add a hidden, empty faux <div>
tag100px
height, just before sticky gets activated the faux div gets height set as 100px
position: fixed
<div> <!-- sticky component -->
<div> {sticky children} </div>
<div class="sticky-faux" style="height: 0px"></div>
</div>
<div> {other divs ...} </div>
Let's say height of the children was 100px
,
<div> <!-- sticky component -->
<div class="sticky" style="position: fixed; ..."> {sticky children} </div>
<div class="sticky-faux" style="height: 100px"></div>
</div>
<div> {other divs ...} </div>
If you think this is fine, I can raise a PR with the changes. So how about this?
I want my sticky nav to retain the width of its containing element. I also only want this to render on the client. How about adding an option that defines the container:
<Sticky container="some-wrapper">
Then check for the DOM and create the styles based on the container:
import {canUseDOM} from 'exenv';
...
const styles = {
position: 'fixed',
top: 0,
left: 0,
right: 0,
zIndex: 1000,
width: '100%'
}
if (canUseDOM && this.props.container) {
const container = document.getElementById(this.props.container);
const boundingClientRect = container.getBoundingClientRect();
styles.left = boundingClientRect.left;
styles.right = boundingClientRect.right;
styles.width = container.clientWidth + 'px';
}
Latest NPM version is still at 4.0.2.
Is this safe to bump the version of react
and react-dom
to 15.0?
I wondered if it possible to use this library to make a sticky 'footer', i.e. an element fixed at the bottom until the user scrolls down the page to the "original" place, above a footer for example ?
I have a case where I need the sticky container to be a section, but don't want to have an extra wrapper around the content. Would it make sense to allow passing in a custom html tag as a prop?
I have a fixed
positioned div and I want to have Sticky
s in it and act like that div is the top of the page.
Is that possible?
as titled =) pls free to ask anything you need
Seemingly the fact that shouldComponentUpdate only checks the sticky state (and not child elements) causes anything within <Sticky />
to only re-render if the sticky state changes.
This ticket is specifically for discussion of supporting <Sticky>
elements attached to in-document scrollable elements.
As an example of such a case:
<div className="scrollable"><StickyContainer><Sticky>...</Sticky></StickyContainer></div>
There are two ways to interpret the expectation in this case:
<Sticky>
is scrolled to the top of the scrollable
element, it sticks to the top of the window.<Sticky>
is scrolled to the top of the scrollable
element, it sticks to the top of the element.Let's leave the first interpretation aside for now, since it's unlikely to be a useful one. This leaves three cases for us to consider.
StickyContainer
.
StickyContainer
.StickyContainer
.Catch 1 (demonstrated here) – scroll
events don't propagate. This implies that the only way to intercept contained scroll events is to subscribe to the scrollable element, which further implies that automagically subscribing to the correct scrollable (non-StickyContainer
) element is either expensive, unreliable, or impossible.
Possible Solution 1.A – we can solve this problem by requiring the user to supply a prop identifying the scrollable element to watch, but sharp edge cases abound.
Possible Solution 1.B – we can restrict scrollable elements we'll respect to StickyContainer
instances (or possibly a ScrollableStickyContainer
subclass).
Catch 2 – position: fixed
(which is used for all of our low-jank positioning) cannot be contained by scrollable elements. This would require us to implement a separate positioning computation for non-window containers.
Possible Solution 2.A – we can require the scrollable element to have position
, and use a position: absolute
based position calculation.
Possible Solution 2.B – we can recalculate a screen-based positioning based on the watched element when appropriate.
Catch 3 – StickyContainer
s are designed to be nested, so that more deeply nested Sticky
elements will stick to one another (a la the timeline example). This is accomplished by StickyContainer
s subscribing to data from their ancestors about other sticky elements. StickyContainer
s being used within a scrollable element context MUST NOT inherit that data.
Possible Solution 3.A – we use the presence of the prop identifying the scrollable element as a sentinel for when we should avoid subscribing to ancestor data.
Possible Solution 3.B – we use a ScrollableStickyContainer
subclass as the data subscription boundary.
This may not represent a complete list of the known concerns or possible solutions, but it seems like one potential solution for solving the general "sub-page" problem might look like this:
<StickyContainer>
...
<Sticky key="first">
I listen to `window`
I stick to `window`
</Sticky>
...
<StickyContainer>
...
<Sticky key="second">
I listen to `window`
I stick to "first"
</Sticky>
...
<ScrollableStickyContainer key="container">
<Sticky key="inner">
I listen to "container"
I stick to "container"
</Sticky>
...
<StickyContainer>
<Sticky key="fourth">
I listen to "container"
I stick to "inner"
</Sticky>
</StickyContainer>
</ScrollableStickyContainer>
</StickyContainer>
</StickyContainer>
To those who are interested in this feature, does this seem like an acceptable solution?
we currently register events on window always:
https://github.com/captivationsoftware/react-sticky/blob/master/lib/sticky.js#L187
would be nice to able to specify the parent component to watch events on. since you can have cases where you want something sticky within a container that is scrollable.
When we make a component Sticky, we take it out of the flow of the document so that we can maintain its position. To prevent document reflow, we also add an appropriate amount of padding to a placeholder element, which maintains the position for everything else on the page. However, the positioned element no longer contributes height to its parent, which means that content changes inside that sticky element don't cause a height change, which means that adjustments that depend on that data aren't recomputed.
An example of this can be seen here.
The header does get sticky on scroll, though it scrolls behind the actually content and is not visible anymore.
I have a Sticky element that has both a top and bottom offset. When the stuck at the bottom of the container, the top of the Sticky element is not in the viewport. When scrolling up, the top of the element doesn't appear until the element is stuck at the top of the container again.
I made a jsbin to show the behaviour http://output.jsbin.com/dupagu
I've been using this component successfully so far. I tried writing a test and attempted fixing this myself but haven't spent enough time in the code base yet.
where is this prop in the source, accordingly to the doc we have this callback hook?
Use the onStickyStateChange prop to fire a callback function when the sticky state changes:
app.jsx
<Sticky onStickyStateChange={this.handleStickyStateChange}>
<header />
</Sticky
Currently when the sticky thing becomes fixed the page jumps up the height of the sticky thing (and vice versa when becoming 'unfixed'). I would say this is a bug.
I am currently doing something like this:
stickyChange(isSticky) {
const parent = document.getElementById('way-header');
if (isSticky) {
const sticky = document.getElementById('sticky-nav-way');
const clientRect = sticky.getBoundingClientRect();
parent.setAttribute('style', 'margin-top:' + clientRect.height + 'px;');
} else {
parent.setAttribute('style', 'margin-top:0px;');
}
}
Something like this should be part of the module, I think.
react version 0.13.3
Uncaught TypeError: Cannot read property 'firstChild' of undefinedReactMount.findComponentRoot
@ app.js:33966ReactMount.findReactNodeByID
@ app.js:33912getNodeFromInstance
@ app.js:33401findDOMNode
@ app.js:40474ReactBrowserComponentMixin.getDOMNode
@ app.js:40412React.createClass.shouldBeSticky
@ app.js:24880React.createClass.handleTick
@ app.js:24890
Confirmed by modifying timeline example like so:
const Lorem = props => {
console.log("LOREM RENDERED", props);
return (
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
);
}
let timeline = [2000, 2010].map((decade) => {
return (
<StickyContainer style={{zIndex: 4}}>
<Sticky style={{zIndex: 3}}>
<h2>{decade}s</h2>
</Sticky>
{ _.range(0,10).map((i) => {
return (
<StickyContainer style={{zIndex: 2}}>
<Sticky>
<h3>{decade + i}</h3>
</Sticky>
<Lorem />
<Lorem />
</StickyContainer>
);
}) }
</StickyContainer>
);
})
This absolute wrecks performance whenever your children are at all complex.
<Sticky onStickyStateChange={this.onStickyStateChange.bind(this)}>
This code does nothing. Helps only something like this:
Sticky.defaultProps.onStickyStateChange = this.onStickyStateChange.bind(this)
All others properties overrides.
Here are the results:
app.js:52954 Uncaught TypeError: Cannot read property 'updateOffset' of undefinedSticky._this.onScroll @ app.js:52954
bundle.js:149 failed, retry № 1 Error: Request to bg page (sync) rejected by timeout(…)
Codepen: http://codepen.io/anon/pen/yJLNxq
In the example, the Sticky
component has an applied class that specifies its width, but once it becomes sticky, that width is overridden (by the width of this.refs.placeholder
).
I have something like:
<StickyContainer> <AppBar /> <Sticky> <HeaderDiv> </HeaderDiv> </Sticky> <div class="col-xs-9"> <Table /> </div> <Sticky class="col-xs-3"> <SomeContent /> </Sticky> </StickyContainer>
I really like to stick only the (to top) and (top right, but positioned right after . I have a strange behavior because of left: 0 property. If you could give me an example how I could do this trick i'll appreciate that. And thank you for your work.
First of all very nice work! I can't seem to find the 3.0 source.
Thanks!
I'd be nice if I could get current Sticky which is active (i.e. has the stickyStyle applied)
Is it possible to make a sticky bottom bar using React Sticky?
It would act the same as the sticky top bar, but be triggered when the page is scrolled up from the bottom.
Thanks!
Thomas
Hard to describe so I uploaded a video. Basically when the window height is just barely tall enough to trigger the stickiness but not tall enough for it to go to its full height it will get into a loop (as long as the user continues to try to scroll).
min-width: 1000px
to body
Sticky element moving horizontally with page, this behaviour is for v5.0.0.
Sticky elements stays in the same place. left
property isn't changing.
Hi,
I really like the component and it helped me a lot.
But I have a question. Is it possible to define a value like bottomOffset
at which the component stops being sticky and starts moving down normal again?
Hey there, I've found out that if we have an structure like this:
<body>
<div style="overflow-y: auto; height: 100%;">
<StickyContainer>
<Sticky>...</Sticky>
</StickyContainer>
</div>
</body>
In this scenario ^. Sticky won't trigger at all, but if we remove the overflow-y or height from the container, it starts working again.
Currently type
expects an element factory method from React.DOM
, it would be good if we could pass in our own components to this.
Usage:
<Sticky component={MyComponent} />
and if you need a div,
<Sticky component='div' />
I'm trying to make react-sticky work on just a portion of the whole screen
I've recreated the timeline demo in a very stripped back fashion and made that work, but if I try to shrink it to less than full screen, the sticky behavior stops working.
I suspect it is missing CSS/HTML rather than a bug, so perhaps more of a documentation issue than code.
Stand alone demo attached. As is it shows working sticky behavior. Comment shows how to recreate the "issued.
Doesn't behave as desired on Firefox 45.0.1 or IE 11.0.9600.18205
Any idea on when version 4 will be in npm?
I am having problems using it straight from github:
In my packages.json file:
"react-sticky": "git://github.com/captivationsoftware/react-sticky.git",
when I do webpack build, it complains:
32% 20/53 build modulesModuleNotFoundError: Module not found: Error: Cannot resolve module 'react-sticky' in /app/reports/client/app/financials
at /app/reports/node_modules/webpack/lib/Compilation.js:229:38
at onDoneResolving (/app/reports/node_modules/webpack/lib/NormalModuleFactory.js:29:20)
at /app/reports/node_modules/webpack/lib/NormalModuleFactory.js:85:20
.
.
resolve module react-sticky in /app/reports/client/app/financials
looking for modules in /app/reports/node_modules
resolve 'file' react-sticky in /app/reports/node_modules
resolve file
/app/reports/node_modules/react-sticky is not a file
/app/reports/node_modules/react-sticky.js doesn't exist
/app/reports/node_modules/react-sticky.jsx doesn't exist
/app/reports/node_modules/react-stickyindex.js doesn't exist
/app/reports/node_modules/react-stickyindex.jsx doesn't exist
/app/reports/node_modules/react-sticky.styl doesn't exist
resolve 'file' or 'directory' /app/reports/node_modules/react-sticky
resolve file
/app/reports/node_modules/react-sticky is not a file
/app/reports/node_modules/react-sticky.js doesn't exist
/app/reports/node_modules/react-sticky.jsx doesn't exist
/app/reports/node_modules/react-stickyindex.js doesn't exist
/app/reports/node_modules/react-stickyindex.jsx doesn't exist
/app/reports/node_modules/react-sticky.styl doesn't exist
resolve directory
directory default file index
resolve file index in /app/reports/node_modules/react-sticky
/app/reports/node_modules/react-sticky/index doesn't exist
/app/reports/node_modules/react-sticky/index.js doesn't exist
/app/reports/node_modules/react-sticky/index.jsx doesn't exist
/app/reports/node_modules/react-sticky/indexindex.js doesn't exist
/app/reports/node_modules/react-sticky/indexindex.jsx doesn't exist
/app/reports/node_modules/react-sticky/index.styl doesn't exist
use lib/index.js from package.json
resolve 'file' or 'directory' lib/index.js in /app/reports/node_modules/react-sticky
resolve file
/app/reports/node_modules/react-sticky/lib/index.js doesn't exist
/app/reports/node_modules/react-sticky/lib/index.js.js doesn't exist
/app/reports/node_modules/react-sticky/lib/index.js.jsx doesn't exist
/app/reports/node_modules/react-sticky/lib/index.jsindex.js doesn't exist
/app/reports/node_modules/react-sticky/lib/index.jsindex.jsx doesn't exist
/app/reports/node_modules/react-sticky/lib/index.js.styl doesn't exist
resolve directory
/app/reports/node_modules/react-sticky/lib/index.js doesn't exist (directory default file)
/app/reports/node_modules/react-sticky/lib/index.js/package.json doesn't exist (directory description file)
This isn't clear from docs and it doesn't seem to work for me after npm install
.
Is there a way for my sticky div to stop being sticky when hitting bottom of page, or footer or to set some offset?
Sometimes a sticky component comes into existence and should already be stuck. Since recomputeState
isn't called until after a scroll or some other trigger, the element jumps.
This would likely be fixed by switching to requestAnimationFrame
as discussed in #86
For a workaround:
const stickImmediately = ref => ref && ref.recomputeState()
return (
<Sticky ref={stickImmediately}>
<Whatever/>
</Sticky>
)
Would it be possible to make an element sticky when the bottom of the element reaches the top of the screen? Almost like a default option for topOffset with a value of the element's height?
when i scroll down over padding-bottom, than padding-bottom change to become 0, and scroll stops.
how to fix this, or my wrong config ?
hope to get your reply as soon as possible.
In the event that two Sticky
nodes are added to the same Container
, both will independently stick when scrolling (as intended). However, if they share horizontal space, they will overlap one another rather than "stack".
This is not an immediate problem (and may sometimes be desirable), but likely warrants some documentation and possibly a warning.
If elements in <Sticky>
are dynamically added/removed or if the height of elements inside are changed, the sticky's padding isn't recalculated.
Video Example:
https://youtu.be/YKk-uyKYxZA
Giving the Sticky component a ref and calling the the update() function only works if the Sticky is not active( isSticky: false)
First, thanks for this, just an opinion here, but the default style value for sticky should not be 0 for the left position, it should be whatever the value is on the component, i have to wrap sticky into another react component to be able to accomplish that:
componentDidMount(){
console.log('sicky mount');
let elm = React.findDOMNode(this.refs.elm);
let rect = elm.getBoundingClientRect();
var sticky = {
position: 'fixed',
top:0,
left:rect.left
};
this.setState({sticky});
}
and later on render
render() {
var sticky = this.state.sticky;
return (
<Sticky ref="elm" stickyStyle={sticky}>
<div>----- eu am a menu -----</div>
</Sticky>
);
}
it works, but it renders the component twice for it to get the y position, and almost never the user will want the component to be at 0 ,0, so here is my case for making the component's left position the default.
I'm using CSS libraries and of course I have fixed header(or some of them call it sticky header/footer).
When I wrap my header component inside Sticky <header>
some conflicts are starting to happen. First there are issues with z-index
but that's not big of a deal. My main issue is that css transition is not happening a well as it used to, Since Sticky <header>
is using fixed positioning.
I'd like to know/see more about header and if I can use it with other headers.
Thanks.
First off, want to say thanks and love this!
Do you have any plans to create an option to disable sticky on mobile?
Thanks,
-Tim
E.g. when you have a markup/CSS like this:
<div className="content">
<Sticky>
<ul className="content-controls"> ...</ul>
</Sticky>
</div>
Where .content has a CSS transform property (e.g. translate), the sticky doesn't work, due to the usage of position:fixed in your script, see:
http://meyerweb.com/eric/thoughts/2011/09/12/un-fixing-fixed-elements-with-css-transforms/
and
http://stackoverflow.com/questions/15194313/webkit-css-transform3d-position-fixed-issue
Hey guys,
First: Thank you for writing this. I'm using this in production, and it just works.
The recent change that caused for version 1.1.0
really should've caused for version 2.0.0
. That is, bumping the major ( if you follow SemVer, which is kinda the standard around here :) ). Why? Because the change was not backwards compatible, since you removed the className in turn for style. I just noticed that it broke my app (because I just depended on ^1.0.4 of react-sticky
).
Well, lesson learned, I now depend on strictly version 1.0.4, since I much prefer the class solution. Just wanted to let you know.
Btw.: Why not just allowing the user to do both? Or give them a callback prop onSticky
so they can decide for themselves?
will try to add more info soon
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.