Use Bootstrap 5 with SvelteKit and Svelte 5
Add @winkintel/bootstrap-svelte to a SvelteKit app with Svelte 5, TypeScript/runes APIs, and Bootstrap 5 CSS while leaving Bootstrap
JavaScript out of the bundle.
Install
Install Bootstrap Svelte and Bootstrap together. Svelte ^5.29.0 is a peer dependency supplied by your SvelteKit app.
pnpm add @winkintel/bootstrap-svelte bootstrap
Add Bootstrap CSS
Bootstrap CSS is required because the components render Bootstrap-compatible classes and markup. Import it once from the root layout or your app stylesheet pipeline.
// src/routes/+layout.ts
import 'bootstrap/dist/css/bootstrap.min.css';
export const prerender = true;
If your SvelteKit project already compiles Sass, import Bootstrap SCSS instead.
// src/app.scss
@import 'bootstrap/scss/bootstrap';
// src/routes/+layout.ts
import '../app.scss';
SSR and Hydration
The package components are Svelte components that render during SSR and hydrate in the browser. Do not load Bootstrap's JavaScript bundle or individual Bootstrap plugins for the same controls; Bootstrap Svelte owns the component behavior.
- Keep DOM-only work in Svelte lifecycle code such as
onMount. - Use component state, for example
$state(false), to control modals, collapses, and offcanvas panels. - Import Bootstrap CSS once so server-rendered HTML and hydrated HTML use the same class styling.
Button Example
Use Button for typed Bootstrap button variants, sizes, links, and events.
<script lang="ts">
import { Button } from '@winkintel/bootstrap-svelte';
</script>
<Button colorVariant="primary" onclick={() => console.log('saved')}>
Save changes
</Button>
Navbar Example
Use Navbar with Nav and Container.
<script lang="ts">
import { Container, Nav, Navbar } from '@winkintel/bootstrap-svelte';
</script>
<Navbar.Root expandOnBreakpoint="lg" class="bg-body-tertiary">
<Container isFluid={true}>
<Navbar.Brand href="/">Acme</Navbar.Brand>
<Navbar.Toggler ariaLabel="Toggle navigation">
<Navbar.TogglerIcon />
</Navbar.Toggler>
<Navbar.Collapse id="mainNavbar">
<Navbar.Nav class="me-auto mb-2 mb-lg-0">
<Nav.Item><Nav.Link isActive={true} href="/">Home</Nav.Link></Nav.Item>
<Nav.Item><Nav.Link href="/settings">Settings</Nav.Link></Nav.Item>
</Navbar.Nav>
</Navbar.Collapse>
</Container>
</Navbar.Root>
Form Example
Use form controls with Svelte bindings and Bootstrap validation classes.
<script lang="ts">
import { Button, Form } from '@winkintel/bootstrap-svelte';
let email = $state('');
let accepted = $state(false);
</script>
<Form.Root method="post" class="needs-validation">
<div class="mb-3">
<Form.InputLabel for="email">Email address</Form.InputLabel>
<Form.EmailInput id="email" name="email" bind:value={email} aria-describedby="email-help" required />
<Form.HelperText id="email-help">Use a work email address.</Form.HelperText>
</div>
<Form.Check class="mb-3">
<Form.CheckInput id="terms" name="terms" bind:checked={accepted} required />
<Form.CheckLabel for="terms">I accept the terms</Form.CheckLabel>
</Form.Check>
<Button type="submit" colorVariant="primary">Create account</Button>
</Form.Root>
Modal Example
Use Modal state instead of Bootstrap JavaScript data attributes.
<script lang="ts">
import { Button, Modal } from '@winkintel/bootstrap-svelte';
let isModalShown = $state(false);
</script>
<Button colorVariant="primary" onclick={() => (isModalShown = true)}>
Open modal
</Button>
<Modal.Root isShown={isModalShown} onHidden={() => (isModalShown = false)}>
<Modal.Dialog>
<Modal.Content>
<Modal.Header isDismissible={true}>
<Modal.Title level={2} class="fs-5">Confirm action</Modal.Title>
</Modal.Header>
<Modal.Body>
<p>Review the details before continuing.</p>
</Modal.Body>
<Modal.Footer>
<Button colorVariant="secondary" onclick={() => (isModalShown = false)}>Cancel</Button>
<Button colorVariant="primary">Continue</Button>
</Modal.Footer>
</Modal.Content>
</Modal.Dialog>
</Modal.Root>