Hide sidebar blocks. #1055

Open
opened 2026-02-04 23:36:12 +03:00 by OVERLORD · 33 comments
Owner

Originally created by @andersonbrantes on GitHub (Feb 20, 2019).

Hello, you are doing a great job with this tool.
Is there a configuration to hide the “recent activity”, “recently updated pages” and “my recently viewed” sidebar blocks?

Originally created by @andersonbrantes on GitHub (Feb 20, 2019). Hello, you are doing a great job with this tool. Is there a configuration to hide the “recent activity”, “recently updated pages” and “my recently viewed” sidebar blocks?
OVERLORD added the 🔨 Feature Request🎨 Design🖌️ View Customization labels 2026-02-04 23:36:12 +03:00
Author
Owner

@ssddanbrown commented on GitHub (Feb 20, 2019):

Hi @andersonbrantes,
Hiding such items is not supported via UI options or anything like that.
If you are handy with CSS it's possible to hide these with CSS rules, placed in the Custom HTML head content setting.

If you can confirm the view you're looking at (Do you have a custom homepage set?) I could help with those rules.

@ssddanbrown commented on GitHub (Feb 20, 2019): Hi @andersonbrantes, Hiding such items is not supported via UI options or anything like that. If you are handy with CSS it's possible to hide these with CSS rules, placed in the `Custom HTML head content` setting. If you can confirm the view you're looking at (Do you have a custom homepage set?) I could help with those rules.
Author
Owner

@andersonbrantes commented on GitHub (Feb 21, 2019):

Ok @ssddanbrown , I will try to do it with CSS...
I didn't know the custom homepage feature, that's a great idea. I am using BookStack for a Wiki that has private and public documents. The main idea is only users with private permissions could see these sidebar blocks(recent activity, recently updated pages, my recently viewed). Do you think it is possible with the custom pages?

@andersonbrantes commented on GitHub (Feb 21, 2019): Ok @ssddanbrown , I will try to do it with CSS... I didn't know the custom homepage feature, that's a great idea. I am using BookStack for a Wiki that has private and public documents. The main idea is only users with private permissions could see these sidebar blocks(recent activity, recently updated pages, my recently viewed). Do you think it is possible with the custom pages?
Author
Owner

@unknowndomain commented on GitHub (Mar 9, 2019):

@andersonbrantes something like this is what I use:
<style>#sidebar { display: none; } [expand-toggle] { visibility: hidden; }</style>
I put this in the page content for our homepage rather than in the custom HTML header where you'd only want:
<style>#sidebar { display: none; }</style>

@unknowndomain commented on GitHub (Mar 9, 2019): @andersonbrantes something like this is what I use: `<style>#sidebar { display: none; } [expand-toggle] { visibility: hidden; }</style>` I put this in the page content for our homepage rather than in the custom HTML header where you'd only want: `<style>#sidebar { display: none; }</style>`
Author
Owner

@andersonbrantes commented on GitHub (Mar 10, 2019):

Hi @unknowndomain... I could use something like that, but, I want this rule only for public pages. This is tricky to do with CSS without a specific identifier(Id or Class) for this. Maybe I can do it with Javascript. But, the best way would be on the server side, I think.

There is a similar issue to what I want to do: #1319

@andersonbrantes commented on GitHub (Mar 10, 2019): Hi @unknowndomain... I could use something like that, but, I want this rule only for public pages. This is tricky to do with CSS without a specific identifier(Id or Class) for this. Maybe I can do it with Javascript. But, the best way would be on the server side, I think. There is a similar issue to what I want to do: #1319
Author
Owner

@unknowndomain commented on GitHub (Mar 11, 2019):

I agree, another solution which would be helpful generally is that the body tag have a few classes on it to help you figure out what kind of page you are on, i.e. <body class="shelf"> or <body class="page public"> or <body class="page private">

That way you could write CSS selectors like body.private or body.page.public.

This is how WordPress handles the issue.

@unknowndomain commented on GitHub (Mar 11, 2019): I agree, another solution which would be helpful generally is that the body tag have a few classes on it to help you figure out what kind of page you are on, i.e. `<body class="shelf">` or `<body class="page public">` or `<body class="page private">` That way you could write CSS selectors like `body.private` or `body.page.public`. This is how WordPress handles the issue.
Author
Owner

@ayyilmaz commented on GitHub (Mar 16, 2020):

I think hiding recent activity block from public is important in terms of security at some cases. Some users who has different roles should see this.

@ayyilmaz commented on GitHub (Mar 16, 2020): I think hiding recent activity block from public is important in terms of security at some cases. Some users who has different roles should see this.
Author
Owner

@HAMFEM commented on GitHub (Mar 27, 2020):

I think hiding recent activity block from public is important in terms of security at some cases. Some users who has different roles should see this.

I fully agree. Pages hidden to some roles appear in the recently changed area to all roles, and they can access it by just clicking the link.
Hiding the side bar is not a good solution, as it makes the navigation less practical in the book/chapter level.

@HAMFEM commented on GitHub (Mar 27, 2020): > I think hiding recent activity block from public is important in terms of security at some cases. Some users who has different roles should see this. I fully agree. Pages hidden to some roles appear in the recently changed area to all roles, and they can access it by just clicking the link. Hiding the side bar is not a good solution, as it makes the navigation less practical in the book/chapter level.
Author
Owner

@haveyougotanypets commented on GitHub (Jul 14, 2020):

On the custom css route it would be helpful if IDs or better still class names set for the entire block section so they can be hidden individually. Currently they seem to be applied somewhat inconsistently.

For example i can set in Custom HTML Head Content:

<style>
#recent-activity {display:none;}
</style>

and it removes the whole block. But if i do:

<style>
#recently-updated-pages {display:none;}
</style>

it removes the block contents but not the header because the id tag has been applied at the sub block of the full recently-updated-pages block content.

If the IDs were set on the top block element for each section that would be helpful fix.

Lastly I would think about using classes rather than IDs as at some point you can guarantee someone is going to want to use the same block twice on a page in a customised theme for whatever reason and if you use IDs it will be invalid html and you've got yourself another support ticket.

Lovely looking wiki so far, looking forward to seeing it improve over time!

@haveyougotanypets commented on GitHub (Jul 14, 2020): On the custom css route it would be helpful if IDs or better still class names set for the entire block section so they can be hidden individually. Currently they seem to be applied somewhat inconsistently. For example i can set in Custom HTML Head Content: ``` <style> #recent-activity {display:none;} </style> ``` and it removes the whole block. But if i do: ``` <style> #recently-updated-pages {display:none;} </style> ``` it removes the block contents but not the header because the id tag has been applied at the sub block of the full recently-updated-pages block content. If the IDs were set on the top block element for each section that would be helpful fix. Lastly I would think about using classes rather than IDs as at some point you can guarantee someone is going to want to use the same block twice on a page in a customised theme for whatever reason and if you use IDs it will be invalid html and you've got yourself another support ticket. Lovely looking wiki so far, looking forward to seeing it improve over time!
Author
Owner

@purpletreesoft commented on GitHub (Jul 25, 2020):

Any progress on this? This is an important feature IMHO. Right sidebar, history, and if possible top-right header content should be hidden from public.

@purpletreesoft commented on GitHub (Jul 25, 2020): Any progress on this? This is an important feature IMHO. Right sidebar, history, and if possible top-right header content should be hidden from public.
Author
Owner

@SloCompTech commented on GitHub (Jan 12, 2021):

Hi, I'm looking forward to see this feature. I'm looking for a way to hide recent activity, especially usernames for guest viewers. Maybe this could be simply implemented to display Someone instead of real username when guest loads the page ?

@SloCompTech commented on GitHub (Jan 12, 2021): Hi, I'm looking forward to see this feature. I'm looking for a way to hide recent activity, especially usernames for guest viewers. Maybe this could be simply implemented to display Someone instead of real username when guest loads the page ?
Author
Owner

@kulpin74 commented on GitHub (Feb 5, 2021):

It's very important feature. In our case we send guest links on specified documents, but all guests can see all documents in Recent activity. Maybe this can be solved through User rights?

@kulpin74 commented on GitHub (Feb 5, 2021): It's very important feature. In our case we send guest links on specified documents, but all guests can see all documents in Recent activity. Maybe this can be solved through User rights?
Author
Owner

@SloCompTech commented on GitHub (Feb 5, 2021):

Yes, possible solution would be, to replace username with Someone and disable link to user based on user role or permission.

@SloCompTech commented on GitHub (Feb 5, 2021): Yes, possible solution would be, to replace username with Someone and disable link to user based on user role or permission.
Author
Owner

@ssddanbrown commented on GitHub (Feb 5, 2021):

It's very important feature. In our case we send guest links on specified documents, but all guests can see all documents in Recent activity. Maybe this can be solved through User rights?

Yes, Users (Including guests) should only be able to see the activity for items they have access to. By default the guest user can view everything but this is configurable by alterting their role.

@ssddanbrown commented on GitHub (Feb 5, 2021): > It's very important feature. In our case we send guest links on specified documents, but all guests can see all documents in Recent activity. Maybe this can be solved through User rights? Yes, Users (Including guests) should only be able to see the activity for items they have access to. By default the guest user can view everything but this is configurable by alterting their role.
Author
Owner

@kulpin74 commented on GitHub (Feb 7, 2021):

It's very important feature. In our case we send guest links on specified documents, but all guests can see all documents in Recent activity. Maybe this can be solved through User rights?

Yes, Users (Including guests) should only be able to see the activity for items they have access to. By default the guest user can view everything but this is configurable by alterting their role.

If this could be the role "List chapter, books, shelf" it would be great. We could send a link for book/chapter but if we dont't give that role - guests will not be able to list anothers books/chapters. This role can affect showing recent activity too. And of course Guests mustn't be able to view User name or another private information.

@kulpin74 commented on GitHub (Feb 7, 2021): > > > > It's very important feature. In our case we send guest links on specified documents, but all guests can see all documents in Recent activity. Maybe this can be solved through User rights? > > Yes, Users (Including guests) should only be able to see the activity for items they have access to. By default the guest user can view everything but this is configurable by alterting their role. If this could be the role "List chapter, books, shelf" it would be great. We could send a link for book/chapter but if we dont't give that role - guests will not be able to list anothers books/chapters. This role can affect showing recent activity too. And of course Guests mustn't be able to view User name or another private information.
Author
Owner

@sarah-arrrgh commented on GitHub (Nov 17, 2021):

I've worked around this for now by hiding the sidebar things we don't need in <style> tags in the HTML head content. The way I've done it means all the sidebar headings aren't visible, but it works ok for what we need it for. Not totally secure as folks can just open developer tools and disable "display: none" to see the content, but means general punters won't see unnecessary clutter.

<style>

/* ----------- hiding sidebar stuff ----------- */

.tri-layout-left-contents h5 {
  display: none;
}

.tri-layout-right-contents h5 {
  display: none;
}

.activity-list {
  display: none;
}

.tri-layout-right-contents .text-muted {
  display: none;
}

#new {
  display: none;
}

#popular {
  display: none;
}

#recently-updated-pages {
  display: none;
}

#page-details > div > div {
  display: none;
}

#sidebar > aside > div:nth-child(2) {
  display: none;
}

#main-content div.grid-card-footer.text-muted {
  display: none;
}

#main-content div.list-sort-container {
  display: none;
}

#header > div > div.text-right {
  display: none;
}

</style>

@sarah-arrrgh commented on GitHub (Nov 17, 2021): I've worked around this for now by hiding the sidebar things we don't need in <style> tags in the HTML head content. The way I've done it means all the sidebar headings aren't visible, but it works ok for what we need it for. Not totally secure as folks can just open developer tools and disable "display: none" to see the content, but means general punters won't see unnecessary clutter. ``` <style> /* ----------- hiding sidebar stuff ----------- */ .tri-layout-left-contents h5 { display: none; } .tri-layout-right-contents h5 { display: none; } .activity-list { display: none; } .tri-layout-right-contents .text-muted { display: none; } #new { display: none; } #popular { display: none; } #recently-updated-pages { display: none; } #page-details > div > div { display: none; } #sidebar > aside > div:nth-child(2) { display: none; } #main-content div.grid-card-footer.text-muted { display: none; } #main-content div.list-sort-container { display: none; } #header > div > div.text-right { display: none; } </style> ```
Author
Owner

@ssddanbrown commented on GitHub (Nov 17, 2021):

Just want to advise, we do have the visual theme system that can be utilised if you need to do something more extensive outside of setting styles, without altering core app files:

https://github.com/BookStackApp/BookStack/blob/master/dev/docs/visual-theme-system.md

Would allow you to override any view file we use and completely remove those parts if desired.

@ssddanbrown commented on GitHub (Nov 17, 2021): Just want to advise, we do have the visual theme system that can be utilised if you need to do something more extensive outside of setting styles, without altering core app files: https://github.com/BookStackApp/BookStack/blob/master/dev/docs/visual-theme-system.md Would allow you to override any view file we use and completely remove those parts if desired.
Author
Owner

@satanahell commented on GitHub (Mar 31, 2022):

Hello everyone, this how my wife hide the right panel for guests users only.
She's using the custom HTML head content in Settings with this code :

<!-- FBU -->
<script type="text/javascript">
window.onload=function()   {  

$links =document.getElementsByTagName('a');
for($link of $links){
   if ($link.href =="https://**PUT YOUR URL HERE**/login"){
   document.querySelector("div.tri-layout-right").style.visibility = 'hidden';
   }
}
}
</script>

It's just hidden i can see it appear and vanish in a second, not quite secure IMO but still better than nothing.
She may will work (or not i don't know) on a custom CSS style using the features mentioned above to hide both panels for guests users.

Have a nice day.

@satanahell commented on GitHub (Mar 31, 2022): Hello everyone, this how my wife hide the right panel for guests users only. She's using the custom HTML head content in Settings with this code : ``` <!-- FBU --> <script type="text/javascript"> window.onload=function() { $links =document.getElementsByTagName('a'); for($link of $links){ if ($link.href =="https://**PUT YOUR URL HERE**/login"){ document.querySelector("div.tri-layout-right").style.visibility = 'hidden'; } } } </script> ``` It's just hidden i can see it appear and vanish in a second, not quite secure IMO but still better than nothing. She may will work (or not i don't know) on a custom CSS style using the features mentioned above to hide both panels for guests users. Have a nice day.
Author
Owner

@ssddanbrown commented on GitHub (Mar 31, 2022):

@satanahell Slightly optimized/earlier-loading version of that if desired:

<script>
	window.addEventListener('DOMContentLoaded', (event) => {
	    const loginShowing = document.querySelector('a[href$="/login"]') !== null;
	    const rightPanel = document.querySelector("div.tri-layout-right");
	    if (loginShowing && rightPanel) {
	    	rightPanel.style.visibility = 'hidden';
	    }
	});
</script>

Note, if you're hiding the right sidebar with a primary aim to hide export options, these can instead be controlled via role permissions (As most right sidebar actions can at some level.)

@ssddanbrown commented on GitHub (Mar 31, 2022): @satanahell Slightly optimized/earlier-loading version of that if desired: ```html <script> window.addEventListener('DOMContentLoaded', (event) => { const loginShowing = document.querySelector('a[href$="/login"]') !== null; const rightPanel = document.querySelector("div.tri-layout-right"); if (loginShowing && rightPanel) { rightPanel.style.visibility = 'hidden'; } }); </script> ``` Note, if you're hiding the right sidebar with a primary aim to hide export options, these can instead be controlled via role permissions (As most right sidebar actions can at some level.)
Author
Owner

@satanahell commented on GitHub (Mar 31, 2022):

@ssddanbrown thanks for your optimized reply, my wife told me that she didn't have your skill level !

I start using this "tricks" in order to expand the main page frame even if i had to hide the left panel too. I still want to display a large google slide into an e-frame on my bookstack instance. Ultimately i find out an acceptable way to achieve that whitout tweaking my bookstack. But i'm still pushing my wife to get a special custom CSS template for this purpose !! 👍

Enjoy your day,

@satanahell commented on GitHub (Mar 31, 2022): @ssddanbrown thanks for your optimized reply, my wife told me that she didn't have your skill level ! I start using this "tricks" in order to expand the main page frame even if i had to hide the left panel too. I still want to display a large google slide into an e-frame on my bookstack instance. Ultimately i find out an acceptable way to achieve that whitout tweaking my bookstack. But i'm still pushing my wife to get a special custom CSS template for this purpose !! 👍 Enjoy your day,
Author
Owner

@TritonB7 commented on GitHub (May 2, 2022):

@satanahell Slightly optimized/earlier-loading version of that if desired:

<script>
	window.addEventListener('DOMContentLoaded', (event) => {
	    const loginShowing = document.querySelector('a[href$="/login"]') !== null;
	    const rightPanel = document.querySelector("div.tri-layout-right");
	    if (loginShowing && rightPanel) {
	    	rightPanel.style.visibility = 'hidden';
	    }
	});
</script>

Note, if you're hiding the right sidebar with a primary aim to hide export options, these can instead be controlled via role permissions (As most right sidebar actions can at some level.)

How would I go about hiding all occurrences of the .tag-item class using this? Instead of just the first occurrence.

@TritonB7 commented on GitHub (May 2, 2022): > @satanahell Slightly optimized/earlier-loading version of that if desired: > > ``` > <script> > window.addEventListener('DOMContentLoaded', (event) => { > const loginShowing = document.querySelector('a[href$="/login"]') !== null; > const rightPanel = document.querySelector("div.tri-layout-right"); > if (loginShowing && rightPanel) { > rightPanel.style.visibility = 'hidden'; > } > }); > </script> > ``` > > Note, if you're hiding the right sidebar with a primary aim to hide export options, these can instead be controlled via role permissions (As most right sidebar actions can at some level.) How would I go about hiding all occurrences of the .tag-item class using this? Instead of just the first occurrence.
Author
Owner

@tacerus commented on GitHub (Sep 24, 2022):

Thanks for the JavaScript snippets - those work great , except that the script seems to load quite late, making the sidebar blocks temporarily visible before they are hidden.

Edit: I figured this out by mixing some of the suggestions here up a bit and having the element hide unless instead of display if a user is logged in:

<style>
  .tri-layout-left { visibility: hidden; }
  .tri-layout-right { visibility: hidden; }
</style>
<script>
	window.addEventListener('DOMContentLoaded', (event) => {
		const loginShowing = document.querySelector('a[href$="/login"]') == null;
		const leftPanel = document.querySelector("div.tri-layout-left");
		const rightPanel = document.querySelector("div.tri-layout-right");
		if (loginShowing) {
			leftPanel.style.visibility = 'visible';
			rightPanel.style.visibility = 'visible';
		}
	});
</script>

This does not quite address the security aspect though - anyone with minor computer knowledge can access the browser console and change the visibility value themselves, gaining easy access to the "hidden" data.

@tacerus commented on GitHub (Sep 24, 2022): Thanks for the JavaScript snippets - those work great ~~, except that the script seems to load quite late, making the sidebar blocks temporarily visible before they are hidden~~. **Edit:** I figured this out by mixing some of the suggestions here up a bit and having the element hide _unless_ instead of display _if_ a user is logged in: ``` <style> .tri-layout-left { visibility: hidden; } .tri-layout-right { visibility: hidden; } </style> <script> window.addEventListener('DOMContentLoaded', (event) => { const loginShowing = document.querySelector('a[href$="/login"]') == null; const leftPanel = document.querySelector("div.tri-layout-left"); const rightPanel = document.querySelector("div.tri-layout-right"); if (loginShowing) { leftPanel.style.visibility = 'visible'; rightPanel.style.visibility = 'visible'; } }); </script> ``` This does not quite address the security aspect though - anyone with minor computer knowledge can access the browser console and change the `visibility` value themselves, gaining easy access to the "hidden" data.
Author
Owner

@foxfabi commented on GitHub (Feb 17, 2023):

It would be helpful if I could show/hide these blocks via the settings.

@foxfabi commented on GitHub (Feb 17, 2023): It would be helpful if I could show/hide these blocks via the settings.
Author
Owner

@RMurphy-Impact commented on GitHub (Mar 7, 2023):

This is a kludgy way to implement it, but I was looking for a similar way to hide recent activity and recent books from public users and this is what I've come up with:
As part of the custom theme, I've edited the below files:
common/activity-list.blade.php
home/parts/sidebar.blade.php

Inside of those two, I've wrapped the drafts, recently updated pages, and activity list code blocks in the following if statement:

@if(userCanOnAny('create', \BookStack\Entities\Models\Book::class) || userCanOnAny('create', \BookStack\Entities\Models\Chapter::class) || userCan('page-create-all') || userCan('page-create-own'))
@endif

This should check that a user has any kind of 'creation' permissions before displaying that section, but can be modified to look for whichever permission fits your use best. This works for our uses, but this will also strip the recent activity lists from logged in users that do not have any creation permissions.

@RMurphy-Impact commented on GitHub (Mar 7, 2023): This is a kludgy way to implement it, but I was looking for a similar way to hide recent activity and recent books from public users and this is what I've come up with: As part of the custom theme, I've edited the below files: common/activity-list.blade.php home/parts/sidebar.blade.php Inside of those two, I've wrapped the drafts, recently updated pages, and activity list code blocks in the following if statement: ``` @if(userCanOnAny('create', \BookStack\Entities\Models\Book::class) || userCanOnAny('create', \BookStack\Entities\Models\Chapter::class) || userCan('page-create-all') || userCan('page-create-own')) @endif ``` This should check that a user has any kind of 'creation' permissions before displaying that section, but can be modified to look for whichever permission fits your use best. This works for our uses, but this will also strip the recent activity lists from logged in users that do not have any creation permissions.
Author
Owner

@code-kungfu commented on GitHub (Mar 21, 2023):

A variation of the above example, if you only wan to hide recent activity from public viewing, you could use this snippet:

<script>
    window.addEventListener('DOMContentLoaded', (event) => {
        const loginShowing = document.querySelector('a[href$="/login"]') !== null;
        const leftActivity = document.querySelector("#recent-activity");
        if (loginShowing && leftActivity) {
            leftActivity.style.visibility = 'hidden';
        }
    });
</script>

Or completely remove it

<script>
	window.addEventListener('DOMContentLoaded', (event) => {
	    const loginShowing = document.querySelector('a[href$="/login"]') !== null;
		const leftActivity = document.getElementById("recent-activity");
	    if (loginShowing && leftActivity) {
	    	leftActivity.innerHTML = "";
	    }
	});
</script>
@code-kungfu commented on GitHub (Mar 21, 2023): A variation of the above example, if you only wan to hide recent activity from public viewing, you could use this snippet: ```html <script> window.addEventListener('DOMContentLoaded', (event) => { const loginShowing = document.querySelector('a[href$="/login"]') !== null; const leftActivity = document.querySelector("#recent-activity"); if (loginShowing && leftActivity) { leftActivity.style.visibility = 'hidden'; } }); </script> ``` Or completely remove it ```html <script> window.addEventListener('DOMContentLoaded', (event) => { const loginShowing = document.querySelector('a[href$="/login"]') !== null; const leftActivity = document.getElementById("recent-activity"); if (loginShowing && leftActivity) { leftActivity.innerHTML = ""; } }); </script> ```
Author
Owner

@ghost commented on GitHub (Mar 28, 2023):

Thanks for the JavaScript snippets - those work great , except that the script seems to load quite late, making the sidebar blocks temporarily visible before they are hidden.

Edit: I figured this out by mixing some of the suggestions here up a bit and having the element hide unless instead of display if a user is logged in:

<style>
  .tri-layout-left { visibility: hidden; }
  .tri-layout-right { visibility: hidden; }
</style>
<script>
	window.addEventListener('DOMContentLoaded', (event) => {
		const loginShowing = document.querySelector('a[href$="/login"]') == null;
		const leftPanel = document.querySelector("div.tri-layout-left");
		const rightPanel = document.querySelector("div.tri-layout-right");
		if (loginShowing) {
			leftPanel.style.visibility = 'visible';
			rightPanel.style.visibility = 'visible';
		}
	});
</script>

This does not quite address the security aspect though - anyone with minor computer knowledge can access the browser console and change the visibility value themselves, gaining easy access to the "hidden" data.

This worked great. Thanks @tacerus.

@ghost commented on GitHub (Mar 28, 2023): > Thanks for the JavaScript snippets - those work great ~, except that the script seems to load quite late, making the sidebar blocks temporarily visible before they are hidden~. > > **Edit:** I figured this out by mixing some of the suggestions here up a bit and having the element hide _unless_ instead of display _if_ a user is logged in: > > ``` > <style> > .tri-layout-left { visibility: hidden; } > .tri-layout-right { visibility: hidden; } > </style> > <script> > window.addEventListener('DOMContentLoaded', (event) => { > const loginShowing = document.querySelector('a[href$="/login"]') == null; > const leftPanel = document.querySelector("div.tri-layout-left"); > const rightPanel = document.querySelector("div.tri-layout-right"); > if (loginShowing) { > leftPanel.style.visibility = 'visible'; > rightPanel.style.visibility = 'visible'; > } > }); > </script> > ``` > > This does not quite address the security aspect though - anyone with minor computer knowledge can access the browser console and change the `visibility` value themselves, gaining easy access to the "hidden" data. This worked great. Thanks @tacerus.
Author
Owner

@retrokit-max commented on GitHub (Apr 5, 2023):

<style>
  .tri-layout-left { visibility: hidden; }
  .tri-layout-right { visibility: hidden; }
</style>
<script>
	window.addEventListener('DOMContentLoaded', (event) => {
		const loginShowing = document.querySelector('a[href$="/login"]') == null;
		const leftPanel = document.querySelector("div.tri-layout-left");
		const rightPanel = document.querySelector("div.tri-layout-right");
		if (loginShowing) {
			leftPanel.style.visibility = 'visible';
			rightPanel.style.visibility = 'visible';
		}
	});
</script>

This works well but just to highlight an edge case: If you have a shelf/book/chapter/page called login then this can stop working and start hiding both panels for logged in users too.

It will continue to work if you include the full link for login to your instance:
const loginShowing = document.querySelector('a[href$="YOUR_PROTOCOL://YOUR_DOMAIN/login"]') == null;

@retrokit-max commented on GitHub (Apr 5, 2023): > ``` > <style> > .tri-layout-left { visibility: hidden; } > .tri-layout-right { visibility: hidden; } > </style> > <script> > window.addEventListener('DOMContentLoaded', (event) => { > const loginShowing = document.querySelector('a[href$="/login"]') == null; > const leftPanel = document.querySelector("div.tri-layout-left"); > const rightPanel = document.querySelector("div.tri-layout-right"); > if (loginShowing) { > leftPanel.style.visibility = 'visible'; > rightPanel.style.visibility = 'visible'; > } > }); > </script> > ``` This works well but just to highlight an edge case: If you have a shelf/book/chapter/page called login then this can stop working and start hiding both panels for logged in users too. It will continue to work if you include the full link for login to your instance: `const loginShowing = document.querySelector('a[href$="YOUR_PROTOCOL://YOUR_DOMAIN/login"]') == null;`
Author
Owner

@cgregaisc commented on GitHub (May 30, 2023):

Hi -- I appreciate all this problem solving. I would like to exclude/hide ONLY the "recent activity" -- the "Book Navigation" that shows up on the left sidebar is very useful to my users, but I would like them to not see the editing activity. The examples above do not seem to work for me -- the event listeners don't work when all i'm doing is removing recent activity. They are being ignored completely. I also don't want public viewers to be able to see the previous versions of the books/pages.

Not sure how to proceed.

@cgregaisc commented on GitHub (May 30, 2023): Hi -- I appreciate all this problem solving. I would like to exclude/hide ONLY the "recent activity" -- the "Book Navigation" that shows up on the left sidebar is very useful to my users, but I would like them to not see the editing activity. The examples above do not seem to work for me -- the event listeners don't work when all i'm doing is removing recent activity. They are being ignored completely. I also don't want public viewers to be able to see the previous versions of the books/pages. Not sure how to proceed.
Author
Owner

@rooteam-deploy commented on GitHub (Feb 14, 2024):

<style>
  .tri-layout-left { visibility: hidden; }
  .tri-layout-right { visibility: hidden; }
</style>
<script>
	window.addEventListener('DOMContentLoaded', (event) => {
		const loginShowing = document.querySelector('a[href$="/login"]') == null;
		const leftPanel = document.querySelector("div.tri-layout-left");
		const rightPanel = document.querySelector("div.tri-layout-right");
		if (loginShowing) {
			leftPanel.style.visibility = 'visible';
			rightPanel.style.visibility = 'visible';
		}
	});
</script>

This works well but just to highlight an edge case: If you have a shelf/book/chapter/page called login then this can stop working and start hiding both panels for logged in users too.

It will continue to work if you include the full link for login to your instance: const loginShowing = document.querySelector('a[href$="YOUR_PROTOCOL://YOUR_DOMAIN/login"]') == null;

This seemed to be working for us until the latest update (23.12). Is an updated method required to hide the sidebar?

@rooteam-deploy commented on GitHub (Feb 14, 2024): > > ``` > > <style> > > .tri-layout-left { visibility: hidden; } > > .tri-layout-right { visibility: hidden; } > > </style> > > <script> > > window.addEventListener('DOMContentLoaded', (event) => { > > const loginShowing = document.querySelector('a[href$="/login"]') == null; > > const leftPanel = document.querySelector("div.tri-layout-left"); > > const rightPanel = document.querySelector("div.tri-layout-right"); > > if (loginShowing) { > > leftPanel.style.visibility = 'visible'; > > rightPanel.style.visibility = 'visible'; > > } > > }); > > </script> > > ``` > > This works well but just to highlight an edge case: If you have a shelf/book/chapter/page called login then this can stop working and start hiding both panels for logged in users too. > > It will continue to work if you include the full link for login to your instance: `const loginShowing = document.querySelector('a[href$="YOUR_PROTOCOL://YOUR_DOMAIN/login"]') == null;` This seemed to be working for us until the latest update (23.12). Is an updated method required to hide the sidebar?
Author
Owner

@hmkim commented on GitHub (Apr 15, 2024):

I'm not familiar with PHP code. Who can provide me with the applied code file? I'd like to see it and apply it myself.

@hmkim commented on GitHub (Apr 15, 2024): I'm not familiar with PHP code. Who can provide me with the applied code file? I'd like to see it and apply it myself.
Author
Owner

@code-kungfu commented on GitHub (May 26, 2024):

For those of you who are still in search of a solution which doesn't involve JavaScript, this might be helpful to you:
https://github.com/code-kungfu/bookstack-cktheme

@code-kungfu commented on GitHub (May 26, 2024): For those of you who are still in search of a solution which doesn't involve JavaScript, this might be helpful to you: https://github.com/code-kungfu/bookstack-cktheme
Author
Owner

@ctrlaltca commented on GitHub (Oct 4, 2024):

It would be really nice if BookStack could integrate the two added permissions from https://github.com/code-kungfu/bookstack-cktheme/ in the main core, to avoid future breakage.

@ctrlaltca commented on GitHub (Oct 4, 2024): It would be really nice if BookStack could integrate the two added permissions from https://github.com/code-kungfu/bookstack-cktheme/ in the main core, to avoid future breakage.
Author
Owner

@AGARES2101 commented on GitHub (Dec 21, 2024):

Explanation of the Code:
Side Panels Visibility:

The script hides the left () and right () panels by default.tri-layout-lefttri-layout-right
If the user is authorized (login page is not displayed), the script makes these panels visible.
Recent Activity Panel:

For unauthorized users (those who see the login page), the "Recent Activity" panel with the ID is hidden.recent-activity
Books Link and Icon:

The script looks for the link to books () and hides it if the user is unauthorized. This includes the icon and text associated with the link.a[data-shortcut="books_view"]
When the Script Executes:

The script runs after the DOM content is fully loaded to ensure all elements are accessible for manipulation.
This setup ensures that unauthorized users do not see sensitive or unnecessary content (e.g., links to books or side panels) while allowing authorized users full access.

<style>
  .tri-layout-left { visibility: hidden; }
  .tri-layout-right { visibility: hidden; }
</style>

<script>
  window.addEventListener('DOMContentLoaded', (event) => {
      // Check if the login page is being displayed
      const loginShowing = document.querySelector('a[href$="/login"]') !== null;

      // Manage the visibility of the side panels
      const leftPanel = document.querySelector("div.tri-layout-left");
      const rightPanel = document.querySelector("div.tri-layout-right");
      if (!loginShowing) { // User is authorized
          if (leftPanel) leftPanel.style.visibility = 'visible';
          if (rightPanel) rightPanel.style.visibility = 'visible';
      }

      // Hide the "Recent Activity" panel for unauthorized users
      const leftActivity = document.querySelector("#recent-activity");
      if (loginShowing && leftActivity) {
          leftActivity.style.visibility = 'hidden';
      }

      // Hide the link and icon for books if the user is unauthorized
      const booksLink = document.querySelector('a[data-shortcut="books_view"]');
      if (loginShowing && booksLink) {
          booksLink.style.display = 'none'; // Hide the link
      }

      // Redirect unauthorized users trying to access /books
      const currentPath = window.location.pathname;
      if (loginShowing && currentPath.startsWith('/books')) {
          // Redirect to the login page
          window.location.href = '/login';
      }
  });
</script>

@AGARES2101 commented on GitHub (Dec 21, 2024): Explanation of the Code: Side Panels Visibility: The script hides the left () and right () panels by default.tri-layout-lefttri-layout-right If the user is authorized (login page is not displayed), the script makes these panels visible. Recent Activity Panel: For unauthorized users (those who see the login page), the "Recent Activity" panel with the ID is hidden.recent-activity Books Link and Icon: The script looks for the link to books () and hides it if the user is unauthorized. This includes the icon and text associated with the link.a[data-shortcut="books_view"] When the Script Executes: The script runs after the DOM content is fully loaded to ensure all elements are accessible for manipulation. This setup ensures that unauthorized users do not see sensitive or unnecessary content (e.g., links to books or side panels) while allowing authorized users full access. ``` <style> .tri-layout-left { visibility: hidden; } .tri-layout-right { visibility: hidden; } </style> <script> window.addEventListener('DOMContentLoaded', (event) => { // Check if the login page is being displayed const loginShowing = document.querySelector('a[href$="/login"]') !== null; // Manage the visibility of the side panels const leftPanel = document.querySelector("div.tri-layout-left"); const rightPanel = document.querySelector("div.tri-layout-right"); if (!loginShowing) { // User is authorized if (leftPanel) leftPanel.style.visibility = 'visible'; if (rightPanel) rightPanel.style.visibility = 'visible'; } // Hide the "Recent Activity" panel for unauthorized users const leftActivity = document.querySelector("#recent-activity"); if (loginShowing && leftActivity) { leftActivity.style.visibility = 'hidden'; } // Hide the link and icon for books if the user is unauthorized const booksLink = document.querySelector('a[data-shortcut="books_view"]'); if (loginShowing && booksLink) { booksLink.style.display = 'none'; // Hide the link } // Redirect unauthorized users trying to access /books const currentPath = window.location.pathname; if (loginShowing && currentPath.startsWith('/books')) { // Redirect to the login page window.location.href = '/login'; } }); </script> ```
Author
Owner

@alycesuza commented on GitHub (Sep 11, 2025):

[PT] Bom dia, irei compartilhar o que funcionou comigo, vale ressaltar que ele só oculta, as funcionalidades ainda rodam, minha necessidade era de ocultar somente para o publico e deixar tudo se tiver logado como admin:

[EN] Good morning, I will share what worked for me. It is worth noting that it only hides; the functionalities still run. My need was to hide it only from the public and let everything be visible if logged in as admin:


<script>
document.addEventListener('DOMContentLoaded', () => {
  // ---- detectar admin por link de settings ou query ?admin=1 | detect admin via settings link or query ?admin=1----
  const url = new URL(window.location.href);
  const forceAdmin = url.searchParams.has('admin');
  const hasSettingsLink = !!document.querySelector(
    'a[href*="/settings"], a[href*="settings"],' +
    'a[title*="Configura"], a[title*="Setting"],' +
    'a[aria-label*="Configura"], a[aria-label*="Setting"]'
  );
  if (forceAdmin || hasSettingsLink) document.body.classList.add('is-admin');

  const isAdmin = document.body.classList.contains('is-admin');

  // ---- HARDEN: remover links e bloquear /revisions para não-admin | remove links and block /revisions for non-admin ----
  if (!isAdmin) {
    document.querySelectorAll('a[href*="/revisions"]').forEach(a => a.remove());
    if (window.location.pathname.includes('/revisions')) window.location.replace('/');
  }

  // ---- ocultar botão "Entrar" para não-admin | hide 'Login' button for non-admins ----
  if (!isAdmin) {
    const loginLink = document.querySelector('a[href*="/login"]');
    if (loginLink) loginLink.remove();
  }

  // ---- HOME (/): manter só "Livros Recentes" na coluna esquerda | keep only 'Recent Books' in the left column ----
  const isHome =
    location.pathname === '/' ||
    (document.querySelector('main h1') && document.querySelector('main h1').textContent.trim().toLowerCase() === 'estantes');

  if (isHome) {
    document.querySelectorAll('.sidebar .recently-updated, .sidebar .recent-activity').forEach(el => el.remove());
    const leftSidebar = document.querySelector('.tri-layout-left');
    if (leftSidebar) {
      leftSidebar.querySelectorAll('section, article, div').forEach(sec => {
        const h = sec.querySelector('h3,h4,h5');
        if (!h) return;
        const t = (h.textContent || '').trim().toLowerCase();
        if (t.includes('páginas recentemente atualizadas') || t.includes('atividades recentes')) sec.remove();
      });
    }
  }

  // ---- SITE-WIDE: ocultar "Atividades recentes" em qualquer página (não-admin) | hide "Recent Activities" on any page (non-admin)----
  if (!isAdmin) {
    document.querySelectorAll('.sidebar .recent-activity, .sidebar .activity-list').forEach(el => el.remove());
    const sidebars = document.querySelectorAll('.tri-layout-left, .tri-layout-right, .sidebar');
    sidebars.forEach(sb => {
      sb.querySelectorAll('section, article, div').forEach(sec => {
        const h = sec.querySelector('h3,h4,h5');
        if (!h) return;
        const t = (h.textContent || '').trim().toLowerCase();
        if (t.includes('atividades recentes') || t.includes('recent activity')) sec.remove();
      });
    });
  }

  // ---- esconder "Ações" SÓ para não-admin em rotas /books/... | hide "Actions" ONLY for non-admins in routes /books/...----
  const path = location.pathname.replace(/\/+$/,'');
  const allowActions = (path === '' || path === '/' || path === '/books' || path === '/shelves');
  const isDeepBookRoute = path.startsWith('/books/') && !allowActions;

  if (!isAdmin && isDeepBookRoute) {
    const right = document.querySelector('.tri-layout-right');
    if (right) {
      right.querySelectorAll('section, article, div').forEach(sec => {
        const h = sec.querySelector('h3,h4,h5');
        if (!h) return;
        const t = (h.textContent || '').trim().toLowerCase();
        if (t === 'ações' || t === 'actions') {
          sec.remove();
        } else {
          const hasInteractive = sec.querySelector('a,button,[role="button"]');
          if ((t.includes('ações') || t.includes('actions')) && !hasInteractive) sec.remove();
        }
      });
    }
  }
});
</script>

<style>
/* laterais visíveis visible sides */
.tri-layout-left, .tri-layout-right { display: block !important; }

/* esconder blocos sensíveis de não-admin (detalhes/revisões/permissões) hide sensitive blocks from non-admins (details/revisions/permissions) */
body:not(.is-admin) .page-details .meta-permissions,
body:not(.is-admin) .entity-meta .meta-permissions,
body:not(.is-admin) .entity-meta .meta-revision,
body:not(.is-admin) .entity-meta .meta-updated,
body:not(.is-admin) .entity-meta .meta-created { display: none !important; }

/* esconder Revisões hide Reviews */
body:not(.is-admin) .entity-sidebar .actions a[href*="/revisions"],
body:not(.is-admin) .entity-sidebar a.page-revisions,
body:not(.is-admin) a[href*="/revisions"] { display: none !important; }

/* esconder botão Entrar (navbar) para não-admin hide Enter button (navbar) for non-admin*/
body:not(.is-admin) header .nav a[href*="/login"],
body:not(.is-admin) .header-links a[href*="/login"] { display: none !important; }


/* HOME: oculta blocos extras, só deixa Livros Recentes hides extra blocks, only shows Recent Books*/
body.home .sidebar .recently-updated,
body.home .sidebar .recent-activity { display: none !important; }

/* SITE-WIDE: defesa extra contra "Atividades recentes" extra defense against "Recent Activities" */
body:not(.is-admin) .sidebar .recent-activity,
body:not(.is-admin) .sidebar .activity-list { display: none !important; }

@alycesuza commented on GitHub (Sep 11, 2025): [PT] Bom dia, irei compartilhar o que funcionou comigo, vale ressaltar que ele só oculta, as funcionalidades ainda rodam, minha necessidade era de ocultar somente para o publico e deixar tudo se tiver logado como admin: [EN] Good morning, I will share what worked for me. It is worth noting that it only hides; the functionalities still run. My need was to hide it only from the public and let everything be visible if logged in as admin: ``` <script> document.addEventListener('DOMContentLoaded', () => { // ---- detectar admin por link de settings ou query ?admin=1 | detect admin via settings link or query ?admin=1---- const url = new URL(window.location.href); const forceAdmin = url.searchParams.has('admin'); const hasSettingsLink = !!document.querySelector( 'a[href*="/settings"], a[href*="settings"],' + 'a[title*="Configura"], a[title*="Setting"],' + 'a[aria-label*="Configura"], a[aria-label*="Setting"]' ); if (forceAdmin || hasSettingsLink) document.body.classList.add('is-admin'); const isAdmin = document.body.classList.contains('is-admin'); // ---- HARDEN: remover links e bloquear /revisions para não-admin | remove links and block /revisions for non-admin ---- if (!isAdmin) { document.querySelectorAll('a[href*="/revisions"]').forEach(a => a.remove()); if (window.location.pathname.includes('/revisions')) window.location.replace('/'); } // ---- ocultar botão "Entrar" para não-admin | hide 'Login' button for non-admins ---- if (!isAdmin) { const loginLink = document.querySelector('a[href*="/login"]'); if (loginLink) loginLink.remove(); } // ---- HOME (/): manter só "Livros Recentes" na coluna esquerda | keep only 'Recent Books' in the left column ---- const isHome = location.pathname === '/' || (document.querySelector('main h1') && document.querySelector('main h1').textContent.trim().toLowerCase() === 'estantes'); if (isHome) { document.querySelectorAll('.sidebar .recently-updated, .sidebar .recent-activity').forEach(el => el.remove()); const leftSidebar = document.querySelector('.tri-layout-left'); if (leftSidebar) { leftSidebar.querySelectorAll('section, article, div').forEach(sec => { const h = sec.querySelector('h3,h4,h5'); if (!h) return; const t = (h.textContent || '').trim().toLowerCase(); if (t.includes('páginas recentemente atualizadas') || t.includes('atividades recentes')) sec.remove(); }); } } // ---- SITE-WIDE: ocultar "Atividades recentes" em qualquer página (não-admin) | hide "Recent Activities" on any page (non-admin)---- if (!isAdmin) { document.querySelectorAll('.sidebar .recent-activity, .sidebar .activity-list').forEach(el => el.remove()); const sidebars = document.querySelectorAll('.tri-layout-left, .tri-layout-right, .sidebar'); sidebars.forEach(sb => { sb.querySelectorAll('section, article, div').forEach(sec => { const h = sec.querySelector('h3,h4,h5'); if (!h) return; const t = (h.textContent || '').trim().toLowerCase(); if (t.includes('atividades recentes') || t.includes('recent activity')) sec.remove(); }); }); } // ---- esconder "Ações" SÓ para não-admin em rotas /books/... | hide "Actions" ONLY for non-admins in routes /books/...---- const path = location.pathname.replace(/\/+$/,''); const allowActions = (path === '' || path === '/' || path === '/books' || path === '/shelves'); const isDeepBookRoute = path.startsWith('/books/') && !allowActions; if (!isAdmin && isDeepBookRoute) { const right = document.querySelector('.tri-layout-right'); if (right) { right.querySelectorAll('section, article, div').forEach(sec => { const h = sec.querySelector('h3,h4,h5'); if (!h) return; const t = (h.textContent || '').trim().toLowerCase(); if (t === 'ações' || t === 'actions') { sec.remove(); } else { const hasInteractive = sec.querySelector('a,button,[role="button"]'); if ((t.includes('ações') || t.includes('actions')) && !hasInteractive) sec.remove(); } }); } } }); </script> <style> /* laterais visíveis visible sides */ .tri-layout-left, .tri-layout-right { display: block !important; } /* esconder blocos sensíveis de não-admin (detalhes/revisões/permissões) hide sensitive blocks from non-admins (details/revisions/permissions) */ body:not(.is-admin) .page-details .meta-permissions, body:not(.is-admin) .entity-meta .meta-permissions, body:not(.is-admin) .entity-meta .meta-revision, body:not(.is-admin) .entity-meta .meta-updated, body:not(.is-admin) .entity-meta .meta-created { display: none !important; } /* esconder Revisões hide Reviews */ body:not(.is-admin) .entity-sidebar .actions a[href*="/revisions"], body:not(.is-admin) .entity-sidebar a.page-revisions, body:not(.is-admin) a[href*="/revisions"] { display: none !important; } /* esconder botão Entrar (navbar) para não-admin hide Enter button (navbar) for non-admin*/ body:not(.is-admin) header .nav a[href*="/login"], body:not(.is-admin) .header-links a[href*="/login"] { display: none !important; } /* HOME: oculta blocos extras, só deixa Livros Recentes hides extra blocks, only shows Recent Books*/ body.home .sidebar .recently-updated, body.home .sidebar .recent-activity { display: none !important; } /* SITE-WIDE: defesa extra contra "Atividades recentes" extra defense against "Recent Activities" */ body:not(.is-admin) .sidebar .recent-activity, body:not(.is-admin) .sidebar .activity-list { display: none !important; } ```
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/BookStack#1055