Settings Panel — Free HTML CSS JS Snippet
Settings Panel · Layouts · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Settings Panel — Sidebar Nav, Profile Form, Notification Toggles & Appearance Controls

A settings panel is a fundamental page in any web application — it centralises user preferences, account management, privacy controls, and appearance customisation. This snippet delivers a complete settings page layout with a left sidebar navigation, four content tabs (Profile, Notifications, Privacy, Appearance), a profile form with avatar, notification toggles, a privacy section with a danger zone, and an appearance tab with theme, accent color, and font size controls.
The two-panel layout
The .panel container uses display: flex with a fixed-width .sidebar (220px) and a flex: 1 .content area. The sidebar has position: relative with border-right separator. The content area uses overflow-y: auto so tall tab content scrolls without the sidebar scrolling. On mobile, this can be adapted to a stacked layout by setting flex-direction: column and giving the sidebar a horizontal scrollable nav row.
Tab switching without a framework
showTab(btn, id) removes .active from all .nav-item and .tab elements, then adds .active to the clicked button and the corresponding tab panel (by ID: tab-profile, tab-notifications, etc.). All tabs are in the DOM simultaneously — only the .active one has display: block via CSS. This keeps tab content persistent between switches, preserving any unsaved form input.
The CSS toggle switch
The notification and privacy toggles use the same CSS-only toggle switch pattern: a hidden checkbox input overlaid by a .track span. When the checkbox is checked, input:checked + .track changes background to indigo, and the ::after pseudo-element (the white circle) translates 20px to the right. The transition on both the background and transform creates the sliding animation.
The appearance controls
The theme selector uses three buttons with .active toggling (setTheme). The accent color picker uses circular buttons; the active one gets a border and an outline ring (outline: 2px solid white, outline-offset: 1px). The font size slider uses a native range input with accent-color: #6366f1 for cross-browser tinted track/thumb styling.
Applying appearance changes to the whole page
To make the accent color and font size controls apply globally, define CSS custom properties on :root: --accent: #6366f1 and --font-size: 14px. In the color picker's onclick handler, call document.documentElement.style.setProperty("--accent", chosenColor). In the font size slider oninput, call document.documentElement.style.setProperty("--font-size", value + "px"). All component CSS that references var(--accent) updates immediately across the page without a reload. Persist the chosen values to localStorage so they survive navigation: localStorage.setItem("accent", color) and localStorage.setItem("fontSize", value). On DOMContentLoaded, read these stored values and apply them before the page renders to avoid a flash of default styles.
Build with AI
Build, Understand, Optimize, and Extend It With AI
You don't need to work out how showTab keeps every tab's content alive in the DOM by hand. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why all four tab panels stay mounted with only display toggled rather than being created and destroyed on switch, or how the input:checked plus .track sibling selector drives the toggle switch animation with zero JavaScript. The same assistant can help optimize it, for example checking whether keeping unsaved form state across tab switches (a deliberate feature here) could leak stale values if the panel is ever reset externally. It's also useful for extending the feature: ask it to sync the active tab to the URL hash so links to a specific settings section are shareable, wire the appearance controls to real CSS custom properties with a localStorage-backed theme, or add per-field validation before Save Changes submits. Treat the code less like a finished artifact and more like a starting point for a conversation.
Prompt to recreate it
Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:
Build a settings panel with sidebar navigation and multiple tabs in plain HTML, CSS, and JavaScript, no framework, no libraries.
Requirements:
- A two-panel flex layout: a fixed-width sidebar with nav buttons on the left, and a flexible content area on the right that scrolls independently (overflow-y: auto) if a tab's content is tall.
- At least four tab panels (for example Profile, Notifications, Privacy, Appearance), all present in the DOM simultaneously. Switching tabs must only toggle a CSS class that controls display none versus block — do not remove or recreate tab content from the DOM on switch, so any unsaved form input in an inactive tab is preserved.
- A single tab-switching function must, in one call, remove the active class from every nav button and every tab panel, then add it back to only the clicked button and its matching panel (matched by an id convention, not a hardcoded lookup table).
- Implement at least one toggle switch using only a hidden checkbox input and a sibling span styled with the input:checked plus sibling CSS selector — the on/off animation (a sliding circle via a pseudo-element transform) must require no JavaScript at all.
- Add a theme picker (System/Light/Dark buttons) and an accent color picker (a row of color swatch buttons) where clicking any option removes the active class from its sibling options and adds it only to the clicked one.
- Add a font-size range slider whose oninput handler updates a live pixel-value label next to it in real time as it is dragged.
- As a documented extension in a code comment, show how the accent color and font size could be applied globally by writing them to CSS custom properties on the document root via style.setProperty, and persisted with localStorage so they survive a reload.Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.
Step by step
How to Use
- 1Click the sidebar nav items to switch tabsClick Profile, Notifications, Privacy, or Appearance in the sidebar to switch the content panel. The active item is highlighted in blue.
- 2Edit the profile formUpdate name, email, and bio fields. Click Save Changes to trigger a save action. The form uses a 2-column CSS Grid with a full-width row for the bio textarea.
- 3Toggle notifications and privacy settingsClick any toggle switch in the Notifications or Privacy tabs to toggle the setting on or off. Add API calls in the toggleSwitch() function to persist changes to the server.
- 4Change theme, accent color, and font sizeIn the Appearance tab, click System/Light/Dark theme buttons, choose an accent color circle, or drag the font size slider. Wire these to a CSS custom property (--accent-color) to apply changes site-wide.
- 5Wire Save Changes to an APIIn the tab-actions Save button click handler, collect form values with FormData or individual input reads, then POST to /api/user/profile. Show a success toast on resolve.
- 6Export for your frameworkClick "JSX" for a React component with useState for the active tab and toggle states. Click "Vue" for a Vue 3 SFC with ref-based tab switching.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
showTab(btn, id) removes .active from all .nav-item and .tab elements (querySelectorAll + forEach), then adds .active to the clicked nav button and the tab div with id="tab-" + id. In CSS, .tab { display: none } and .tab.active { display: block }. All tab content stays in the DOM, so unsaved form values are preserved when switching between tabs.
The toggle is a label containing a hidden checkbox and a .track span. The checkbox handles the checked state natively. The CSS rule input:checked + .track changes background to indigo. The .track::after pseudo-element is the white circle, positioned left: 3px by default. input:checked + .track::after uses transform: translateX(20px) to slide it right. The transition on both properties creates the animation.
Define CSS custom properties on :root: --accent: #6366f1; --font-size: 14px. In setColor(), read the button's background color and set document.documentElement.style.setProperty("--accent", color). In the font size slider oninput, set document.documentElement.style.setProperty("--font-size", value + "px"). Reference these in all component CSS.
In React, manage the active tab with const [tab, setTab] = useState("profile"). Render each tab section conditionally: {tab === "profile" && <ProfileTab />}. For toggle switches, use const [prefs, setPrefs] = useState({ analytics: true, marketing: false }) and pass values/setters as props. In Vue 3, use ref("profile") for the active tab and a reactive() object for toggle states. The sidebar nav items call setTab / tab.value on click. For URL-based tab persistence (so the back button works and links to specific tabs are shareable), sync the active tab with the URL hash: on mount, read window.location.hash to set the initial tab; in setTab(), update window.location.hash = tab so the URL reflects the current section. Listen to the hashchange event to handle browser back/forward navigation between tabs without a full route change.