Existing Projects

Adding a design system to an existing application is different from starting fresh. Davis applies global styles that can conflict with your current CSS. This guide walks you through standalone mode — a scoped approach that lets Davis components live alongside your existing styles without interference. Using this approach, you can incrementally adopt Davis in parts of your app without a full all-or-nothing migration.

If you're starting a new project, follow the standard Installation guide instead.


Why Standard Mode Breaks Existing Apps

The standard Davis setup imports base.css, which applies styles globally:

What changesHow it changesWhat breaks
Font familySets html { font-family: Inter, ... }Your app's font changes everywhere
Heading sizesApplies Major Third scale to all h1h6Your existing headings resize unexpectedly
Focus ringsAdds *:focus-visible outline to all elementsFocus styles clash with your existing ones
CSS custom propertiesSets --davis-* variables on :rootGenerally safe, but pollutes the global namespace
Tailwind PreflightResets margins, padding, borders on all elementsYour non-Tailwind CSS breaks in subtle ways

In a new project, these global styles are the foundation you build on. In an existing project, they'll cause widespread changes you probably aren't ready to make all at once.


Standalone Mode Setup

Standalone mode scopes all Davis styles under a .davis CSS class. Nothing leaks outside that boundary.

1. Install Packages

Same packages as standard mode:

npm install @libretexts/davis-react @libretexts/davis-core

Peer dependencies:

npm install @headlessui/react react react-dom tailwindcss

2. Import Standalone Styles

Import the stylesheet in your app's entry point:

import "@libretexts/davis-react/styles.css";

This stylesheet includes all Davis styles. DavisProvider handles scoping automatically — wrapping your components in DavisProvider creates the .davis boundary that keeps styles contained. You do not need a separate standalone stylesheet.

3. Wrap Components with DavisProvider

Every Davis component must be rendered inside a DavisProvider. The provider creates the .davis wrapper <div> that activates scoped styles:

import { DavisProvider, Button } from "@libretexts/davis-react";

function App() {
  return (
    <div>
      <h1>My Existing App</h1>
      {/* This heading keeps your app's original styles */}

      <DavisProvider>
        <Button>This button is styled by Davis</Button>
      </DavisProvider>
    </div>
  );
}

Integration Patterns

Page-section approach

Wrap individual sections where you want Davis components. Your existing UI remains untouched everywhere else:

import { DavisProvider, Card, Button, Input } from "@libretexts/davis-react";

function Dashboard() {
  return (
    <main>
      {/* Existing app header — not affected by Davis */}
      <header className="my-existing-header">
        <h1>Dashboard</h1>
      </header>

      {/* Davis-powered section */}
      <DavisProvider className="mt-8">
        <Card>
          <Card.Header>
            <h2>Quick Actions</h2>
          </Card.Header>
          <Card.Body>
            <Input label="Search" placeholder="Find something..." />
            <Button className="mt-4">Go</Button>
          </Card.Body>
        </Card>
      </DavisProvider>

      {/* Another existing section — still untouched */}
      <section className="my-existing-section">
        <p>This content uses your original styles.</p>
      </section>
    </main>
  );
}

Full-app wrapper

If you're gradually migrating your entire app to Davis, wrap everything in a single provider:

import { DavisProvider } from "@libretexts/davis-react";

function App() {
  return (
    <DavisProvider>
      {/* Everything inside gets Davis styles */}
      <RouterOutlet />
    </DavisProvider>
  );
}

This is a good stepping stone toward standard mode. When you're ready to complete the migration, see Migrating to Standard Mode below.

Multiple providers

You can use multiple DavisProvider instances on the same page. Each creates its own .davis scope:

function Page() {
  return (
    <>
      <DavisProvider>
        <Card>
          <Card.Body>Section A</Card.Body>
        </Card>
      </DavisProvider>

      <div className="legacy-content">
        <p>Untouched by Davis.</p>
      </div>

      <DavisProvider>
        <Card>
          <Card.Body>Section B</Card.Body>
        </Card>
      </DavisProvider>
    </>
  );
}

There's no performance penalty — DavisProvider is a lightweight wrapper (<div className="davis">) with a React context.


What Gets Scoped

Style categoryStandard modeStandalone mode
CSS custom properties:root (global).davis (scoped)
Font familyhtml (global).davis (scoped)
Heading typographyh1h6 (global).davis h1.davis h6 (scoped)
Focus rings*:focus-visible (global).davis *:focus-visible (scoped)
Tailwind PreflightAll elements (global)Disabled — partial reset under .davis only
Tailwind utilitiesNormal specificityBoosted via important: '.davis'
Box-sizing resetAll elements (via Preflight).davis * only

Troubleshooting

Headless UI portals

Some Davis components use Headless UI, which renders popovers, menus, and dialogs through portals. Portals attach elements to document.body, which is outside the .davis wrapper.

Davis components handle this automatically — Headless UI's Portal renders within the nearest parent context. If you encounter unstyled portaled content, ensure the DavisProvider is high enough in your component tree to contain the trigger element.

Styles not applying to the wrapper element

DavisProvider renders a <div className="davis">. Davis utility classes on this element need the .davis ancestor selector to activate. Since the div is the .davis element (not a descendant of one), utilities applied directly to it work because important: '.davis' makes .davis .utility match .davis.utility as well.

If you need to style the wrapper itself, use the className prop:

<DavisProvider className="p-4 bg-surface">
  {/* content */}
</DavisProvider>

Class name conflicts

If your app already uses a CSS class called .davis, you'll get style collisions. This is unlikely but if it happens, you'll need to rename your existing class — the .davis scope name is not configurable.


Migrating to Standard Mode

When your app is fully using Davis and you're ready to remove the scoping layer:

  1. Replace the standalone stylesheet import with the standard one:
    @import 'tailwindcss';
    @import '@libretexts/davis-react/styles.css';
    
  2. Remove DavisProvider wrappers — components work without them in standard mode
  3. Test thoroughly — global base styles will now apply to your entire app

This is a one-way migration. Once you switch to standard mode, all elements in your app will inherit Davis's global styles (font family, heading scale, focus rings, Preflight resets).