Skip to content

feat(web): add sticky date headers#25887

Open
didekoning wants to merge 14 commits intoimmich-app:mainfrom
didekoning:feature/sticky_headers
Open

feat(web): add sticky date headers#25887
didekoning wants to merge 14 commits intoimmich-app:mainfrom
didekoning:feature/sticky_headers

Conversation

@didekoning
Copy link
Contributor

@didekoning didekoning commented Feb 4, 2026

Description

I’ve made the day headers sticky, as requested in #1667. This makes it much easier to keep track of the date photos were taken while scrolling through large timelines.

This implementation replaces the transform-based positioning used for the Month sections with top and left positioning, since position: sticky does not work correctly when an element is inside a transformed parent container. This change may have a small performance impact, but because the original transform positioning was not actively animated (except during resize), the impact should be minimal.

To help mitigate any performance concerns, I also improved the month title checkbox animation by switching it from animating width to animating transform, which is generally more performant.

This makes it easier to see what date photos were taken when you are halfway through scrolling a large section of the timeline.

Fixes # #1667

How Has This Been Tested?

  • I've tested this on multiple screen sizes in Google Chrome and Firefox.

Screenshots (if appropriate)

immich_demo_small.mov

Checklist:

  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation if applicable
  • I have no unrelated changes in the PR.
  • I have confirmed that any new dependencies are strictly necessary.
  • I have written tests for new code (if applicable)
  • I have followed naming conventions/patterns in the surrounding code
  • All code in src/services/ uses repositories implementations for database calls, filesystem operations, etc.
  • All code in src/repositories/ is pretty basic/simple and does not have any immich specific logic (that belongs in src/services/)

Please describe to which degree, if any, an LLM was used in creating this pull request.

An LLM was used for code explaination and to help find the correct Tailwind classes.
...

@didekoning didekoning marked this pull request as draft February 4, 2026 12:03
@didekoning didekoning marked this pull request as ready for review February 5, 2026 07:41
@didekoning didekoning marked this pull request as draft February 6, 2026 14:09
@didekoning didekoning marked this pull request as ready for review February 6, 2026 14:09
@midzelis
Copy link
Collaborator

midzelis commented Feb 6, 2026

I'll do a perf test on this within the next few days

@bwees bwees changed the title Add sticky date headers to the web version feat(web): add sticky date headers Feb 14, 2026
@midzelis
Copy link
Collaborator

midzelis commented Mar 3, 2026

I tested the perf (synthetically) and even though translate3d is faster (in the absolute sense) it is only microseconds faster, and doesn't impact 60fps (16ms per frame) or 120fps (8ms per frame) rendering.

Copy link
Member

@danieldietzler danieldietzler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When scrolling back up or when using the scrubber, the header sometimes disappears

data-group
style:position="absolute"
style:transform={`translate3d(${absoluteWidth}px,${dayGroup.top}px,0)`}
style:left={`${absoluteWidth}px`}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be style:inset-inline-start for RTL languages, see also #26513

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I need to find some time to find a way that both works with my change and works with RTL languages. Since the change to left was intentional to fix some issues with the fixed header.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inset-inline-start is just the logical/rtl-friendly css property for offsetting something from the 'left' margin that we're used to. In general, it is always correct to replace left with inset-inline-start, unless you're dealing for example with pixel offsets of the face bounding boxes in an image.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants