You can restyle almost everything on your DSAR form, from a quick color swap with no code to a full redesign with your own stylesheet. Changes stack in three layers, and each one overrides the one before it.
--osano- CSS variables in your stylesheet. One line can recolor every button, border, or font on the form.osano- class names to change layout, corners, spacing, hover effects, and visibility.Adding your stylesheet
Your stylesheet loads after Osano's built-in styles, so your rules win whenever the selectors are equally specific. If the URL can't be read, Osano skips it silently and shows the default form. Full technical reference: Customizing the DSAR Form.
These eight settings live in the form's styling settings in Osano. Set them even if you also use a stylesheet: Osano uses the background color to pick readable arrow and checkmark colors, and CSS alone can't do that.
| Setting | What it changes | Default | Your value |
|---|---|---|---|
| Primary color | Buttons, focus rings, selected options, checked boxes, links | #7a3ff1 | |
| Primary readable color | Text on top of the primary color, such as button labels. Auto-picked if left blank. | Auto (black or white) | |
| Form background color | The page area behind the form | #FAF9FB | |
| Field text color | Text inside fields and field labels | #190E43 | |
| Error color | Error borders and error messages | #ef4444 | |
| Required asterisk color | The * next to required fields | #ef4444 | |
| Helper text color | Help text under fields and instructional text | #6b7280 | |
| Disabled readable color | Text and spinners on disabled controls. Auto-picked if left blank. | Auto (black or white) |
Tip: if your primary color is a medium gray or a muted tone, set the readable color yourself. The auto-pick leans toward white text.
Redefine any of these inside a :root { } block in your stylesheet. Each one recolors everything that uses it across the form. Fill in the last column as you plan your theme.
:root {
--osano-color-primary: #0a7cff;
--osano-color-bg-light-gray: #f4f7fb;
}| Variable | Controls | Default | Your value |
|---|---|---|---|
--osano-color-primary | Main brand color: buttons, focus ring, links | #7a3ff1 | |
--osano-color-primary-dark | Hover and pressed shades of the primary | 2% darker than primary | |
--osano-color-primary-readable | Text on the primary color | Auto | |
--osano-color-primary-transparent | Soft primary tint, such as focus halos | Primary at 50% | |
--osano-color-primary-text | Main text, labels, field values | #190E43 | |
--osano-color-text-secondary | Secondary text | #403653 | |
--osano-color-text-subtle | Descriptions and quieter text | #726A82 | |
--osano-color-text-super-subtle | Placeholder text in fields | #A099AF | |
--osano-color-grayscale-950 | Darkest neutral | #0E0D10 | |
--osano-color-bg-light-gray | Page background behind the form | #FAF9FB | |
--osano-color-bg-table-header | Tinted panels and table headers | #F5F0FF | |
--osano-color-bg-default | Field backgrounds | #FFFFFF | |
--osano-color-background | Same as field background | #FFFFFF | |
--osano-color-background-dark | Field background, slightly darker | 2% darker | |
--osano-color-bg-card | Card backgrounds | #FFFFFF | |
--osano-color-bg-button-secondary | Secondary button background | #FFFFFF | |
--osano-color-border-subtle | Light dividers and card outlines | #E7E5EB | |
--osano-color-border-default | Field and control borders | #D5D1DC | |
--osano-color-disabled-bg | Disabled control background | #D5D1DC | |
--osano-color-disabled-readable | Text on disabled controls | Auto | |
--osano-color-disabled-text | Disabled field text | Main text at 50% | |
--osano-color-error | Error borders and messages | #ef4444 | |
--osano-color-error-dark | Darker error shade | 2% darker | |
--osano-color-required | Required * marker | #ef4444 | |
--osano-color-helper-text | Help text under fields | #6b7280 | |
--osano-color-success-bg | Success message background | #DCFCE7 | |
--osano-color-text-success | Success message text | #016630 |
Some pieces of the form, like individual cards, may set their own background directly. If a token change doesn't show up on a piece, style that piece with its class (see Component classes).
These control corners, shadows, and type across the whole form. Radius values accept any CSS border-radius, so you can use four values for asymmetric corners (for example 0 24px 0 24px).
Corners and shadow
| Variable | Controls | Default | Your value |
|---|---|---|---|
--osano-radius-md | Fields, buttons, small controls | 6px | |
--osano-radius-lg | Cards and panels | 10px | |
--osano-shadow-xl | Card shadow | Soft two-layer shadow |
Typography
The form ships with DM Sans. To use your own font, load it at the top of your stylesheet with @import (for example from Google Fonts), then set --osano-font-family.
| Variable | Controls | Default | Your value |
|---|---|---|---|
--osano-font-family | Every piece of text on the form | "DM Sans", Arial, sans-serif | |
--osano-heading-lg-size | Large heading size | 20px | |
--osano-heading-lg-weight | Large heading weight | 700 | |
--osano-heading-lg-line-height | Large heading line height | 24px | |
--osano-heading-lg-letter-spacing | Large heading letter spacing | -0.4px | |
--osano-heading-sm-size | Small heading size | 16px | |
--osano-heading-sm-weight | Small heading weight | 700 | |
--osano-heading-sm-line-height | Small heading line height | 22px | |
--osano-heading-sm-letter-spacing | Small heading letter spacing | -0.2px | |
--osano-body-size | Body text size | 14px | |
--osano-body-weight | Body text weight | 400 | |
--osano-body-line-height | Body text line height | 20px | |
--osano-caption-size | Small text, including request descriptions | 12px | |
--osano-caption-weight | Small text weight | 500 | |
--osano-caption-line-height | Small text line height | 16px | |
--osano-caption-letter-spacing | Small text letter spacing | 0.12px | |
--osano-font-weight-medium | Medium emphasis weight | 600 |
Careful with caption letter spacing. Request descriptions use it, so wide values like 1.5px make them hard to read.
Every osano- class below is a stable hook you can style safely. Ignore the random-looking classes next to them (like VVnr1s_k); those are generated and can change with any Osano release.
To beat Osano's defaults without !important, start your selectors with .osano-root, for example .osano-root .osano-card { }.
| Area | Class | What it is | Ideas |
|---|---|---|---|
| Page | osano-root | Outermost wrapper of the whole form | Scope all your rules under it |
| Page | osano-root__container | Main inner wrapper | Page padding, max width, a logo via ::before |
| Page | osano-body | Body area of the form | Background, spacing |
| Page | osano-container | Content column | Top spacing, gaps between sections |
| Page | osano-header | Header area | Shrink or remove padding |
| Jurisdiction | osano-container__localization-message / osano-localization-message | "We've detected your jurisdiction" message | Restyle or hide |
| Jurisdiction | osano-form__location-select / osano-location-select | Location dropdown | Restyle or hide |
| Jurisdiction | osano-location-select__button-wrapper / osano-button-wrapper | Wrapper around the dropdown button | Alignment |
| Jurisdiction | osano-location-select__open-button / osano-open-button | The dropdown button | Pill shape, border, font |
| Jurisdiction | osano-location-select__open-chevron / osano-open-chevron | Arrow icon in the dropdown | Color, size, rotation |
| Jurisdiction | osano-location-select__over-select / osano-over-select | Invisible layer used to open the list | Leave as is |
| Header | osano-container__control-header / osano-control-header | Header block above the request list | Title styling, or hide |
| Requests | osano-container__card-list / osano-card-list | Grid holding the request options | Columns, gap |
| Requests | osano-card-list__card | One request option tile | Colors, corners, hover effects |
| Requests | osano-card | Card panels (tiles and larger panels) | Background, border, shadow |
| Requests | osano-card__header | Request title inside a tile | Font, color |
| Requests | osano-card__body | Request description inside a tile | Color, size |
| Requests | osano-card__icon / osano-icon | Arrow icon on a tile | Circle background, hover rotation |
| Form | osano-form | The request form itself | Padding |
| Form | osano-field | A field with its label | Label styling, spacing |
| Form | osano-input | Text inputs, selects, text areas | Border, background, focus |
| Form | osano-button | Primary buttons, such as Submit | Shape, color, hover |
Double class names (a / b) point at the same element. Use either one.
A few elements only carry a generated class. Don't target those, because they break on the next Osano release. Use one of these three approaches instead.
1. Test IDs. Some elements carry a data-testid attribute that stays stable.
| Selector | What it targets |
|---|---|
[data-testid="form-title"] | The request form's title, such as "Delete my personal information" |
[data-testid="form-description"] | The short description under that title |
.osano-root [data-testid="form-title"] {
color: #ffffff;
}2. The parent of a known element. :has() selects an element by what's inside it. This is how you reach an unnamed wrapper, like the box around the jurisdiction message.
/* the element that directly contains the jurisdiction message */
.osano-root :has(> .osano-localization-message) {
display: none;
}3. Position in a list. :nth-child() styles items by order, which is how you give each request tile its own color.
.osano-root .osano-card-list > :nth-child(odd) { --tile-bg: #F0E7FA; }
.osano-root .osano-card-list > :nth-child(even) { --tile-bg: #DDF6EA; }
.osano-root .osano-card-list__card { background: var(--tile-bg); }To find what an element carries, right-click it in your browser, choose Inspect, and look for osano- classes or a data-testid on it or its parent.
Copy any of these into your stylesheet and change the values to match your brand.
Brand color and font
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap");
:root {
--osano-color-primary: #0a7cff;
--osano-color-primary-readable: #ffffff;
--osano-font-family: "Inter", Arial, sans-serif;
}Match your site's page background
:root { --osano-color-bg-light-gray: transparent; }
body { background: #f4f7fb; }Gradient background with see-through panels
body {
min-height: 100vh;
background: linear-gradient(155deg, #180D43, #7A3FF1, #F09F92);
background-attachment: fixed;
}
.osano-root .osano-card {
background: rgba(24, 13, 67, 0.4);
backdrop-filter: blur(18px);
border: 1px solid rgba(255, 255, 255, 0.2);
}Square or asymmetric corners
:root {
--osano-radius-md: 0;
--osano-radius-lg: 0 32px 0 32px;
}Colorful request tiles with a hover lift
.osano-root .osano-card-list__card {
background: #F0E7FA;
border: 2px solid #0E0416;
box-shadow: 6px 6px 0 #0E0416;
transition: transform 200ms ease, box-shadow 200ms ease;
}
.osano-root .osano-card-list__card:hover {
transform: translate(-3px, -3px);
box-shadow: 9px 9px 0 #0E0416;
}Pill-shaped buttons
.osano-root .osano-button {
border-radius: 999px;
padding: 0.85rem 2rem;
font-weight: 700;
}Add your logo to the top right
This logo is decorative only. Screen readers skip it, and it can't be a link.
.osano-root .osano-root__container::before {
content: "";
display: block;
width: 100%;
height: 36px;
margin-bottom: 1rem;
background: url("https://yourcompany.com/logo.svg") no-repeat right center / contain;
}Hide the jurisdiction banner
Visitors can no longer change their location, so anyone on a VPN or traveling sees the rights for wherever they were detected. Restyling the banner is usually the better choice.
.osano-root :has(> .osano-localization-message),
.osano-root .osano-control-header {
display: none;
}Change text color on the request form page
.osano-root [data-testid="form-title"],
.osano-root [data-testid="form-description"] {
color: #ffffff;
}Underline-style fields
.osano-root .osano-input {
border: 0;
border-bottom: 2px solid #D5D1DC;
border-radius: 0;
background: transparent;
}
.osano-root .osano-input:focus {
border-bottom-color: var(--osano-color-primary);
outline: none;
}Best practices
:root block at the top of your file, so a rebrand is a few edits..osano-root instead of using !important. It keeps your file predictable and easy to change.osano- classes, data-testid, or :has().@media (prefers-reduced-motion: reduce) and turn it off there.Troubleshooting
| What you see | Likely cause | Fix |
|---|---|---|
| Nothing changed | The browser cached the old file | Hard refresh, or add ?v=2 to the end of your stylesheet URL |
| Nothing changed at all | The URL isn't public or isn't https:// | Open the URL in a private browser window to confirm it loads |
| A token change doesn't show on one piece | That piece sets its color directly | Style it with its osano- class under .osano-root |
| Your rule loses to Osano's | Selector isn't specific enough | Add .osano-root in front of it |
| Styles broke after an Osano update | You targeted a generated class | Switch to an osano- class or data-testid |
| Arrows or checkmarks are hard to see | The palette background doesn't match your CSS background | Set Form background color in the palette to match |
| Text looks too spaced out | Caption letter spacing set too wide | Set --osano-caption-letter-spacing back to 0.12px or lower |
| An empty bar remains after hiding something | Its wrapper is still visible | Hide the wrapper with :has(> .the-hidden-class) |
You don't need to write CSS yourself. Paste this guide into an AI assistant like Claude along with the prompt below, describe what you want in plain words, and it will write the stylesheet for you.
How to use it
The prompt
You are a front-end developer helping me style an Osano DSAR (privacy request) form with a custom CSS stylesheet. Below is the full customization guide for this form. Use only what it documents.
<guide>
[PASTE THIS ENTIRE GUIDE HERE]
</guide>
Here is what I want my form to look like, in plain words:
<request>
[DESCRIBE YOUR CHANGES HERE]
</request>
Rules for the stylesheet you write:
- Return one complete CSS file I can host as-is.
- Put all colors, fonts, and corner values in a single :root block at the top.
- Change --osano- design tokens first. Use component classes only when a token can't do the job.
- Target only osano- classes, data-testid attributes, or :has(). Never use random-looking generated class names.
- Start component selectors with .osano-root instead of using !important.
- Load any custom fonts with @import on the very first line.
- Keep text contrast at 4.5:1 or higher, keep visible focus outlines, and turn off motion inside @media (prefers-reduced-motion: reduce).
- Add a short comment above each section explaining what it changes.
After the CSS, tell me:
1. Which palette settings I should also set in Osano, and the values.
2. Anything you couldn't do with the documented classes, and what I should inspect in my browser and send you to finish it.
If my request is unclear or conflicts with accessibility, ask me before writing the CSS.Example requests
Always preview the result before publishing. If something doesn't change, send the assistant a screenshot plus the HTML of that element (right-click, Inspect, then right-click the highlighted line and Copy element).