Getting started
Implementing a Popover
In this quick tutorial, we will install and style the Popover component.
1. Install the library
Install the component from your command line.
pnpm add akar
yarn add akar
npm install akar
bun add akar
2. Import the parts
Import and structure the parts.
<!-- Popover.vue -->
<script setup lang="ts">
import { PopoverArrow, PopoverClose, PopoverContent, PopoverPortal, PopoverRoot, PopoverTrigger } from 'akar';
</script>
<template>
<PopoverRoot>
<PopoverTrigger>More info</PopoverTrigger>
<PopoverPortal>
<PopoverContent>
Some more info...
<PopoverClose />
<PopoverArrow />
</PopoverContent>
</PopoverPortal>
</PopoverRoot>
</template>
3. Add your styles
Add styles where desired.
<template>
<PopoverRoot>
<PopoverTrigger class="PopoverTrigger">
More info
</PopoverTrigger>
<PopoverPortal>
<PopoverContent class="PopoverContent">
Some more info...
<PopoverClose />
<PopoverArrow class="PopoverArrow" />
</PopoverContent>
</PopoverPortal>
</PopoverRoot>
</template>
<style>
.PopoverTrigger {
background-color: white;
border-radius: 4px;
}
.PopoverContent {
border-radius: 4px;
padding: 20px;
width: 260px;
background-color: white;
}
.PopoverArrow {
background-color: white;
}
</style>
Demo
Here's a complete demo.
<script setup lang="ts">
import { PopoverArrow, PopoverClose, PopoverContent, PopoverPortal, PopoverRoot, PopoverTrigger } from 'akar';
import './styles.css';
</script>
<template>
<div class="akar-demo akar-demo-Popover">
<PopoverRoot>
<PopoverTrigger
class="IconButton"
aria-label="Update dimensions"
>
<PIcon name="i-lucide-sliders-horizontal" />
</PopoverTrigger>
<PopoverPortal>
<PopoverContent
side="bottom"
:side-offset="5"
class="PopoverContent"
>
<div :style="{ display: 'flex', flexDirection: 'column', gap: 10 }">
<p class="Text">
Dimensions
</p>
<fieldset class="Fieldset">
<label
class="Label"
for="width"
> Width </label>
<input
id="width"
class="Input"
defaultValue="100%"
>
</fieldset>
<fieldset class="Fieldset">
<label
class="Label"
for="maxWidth"
> Max. width </label>
<input
id="maxWidth"
class="Input"
defaultValue="300px"
>
</fieldset>
<fieldset class="Fieldset">
<label
class="Label"
for="height"
> Height </label>
<input
id="height"
class="Input"
defaultValue="25px"
>
</fieldset>
<fieldset class="Fieldset">
<label
class="Label"
for="maxHeight"
> Max. height </label>
<input
id="maxHeight"
class="Input"
defaultValue="none"
>
</fieldset>
</div>
<PopoverClose
class="PopoverClose"
aria-label="Close"
>
<PIcon name="i-lucide-x" />
</PopoverClose>
<PopoverArrow class="PopoverArrow" />
</PopoverContent>
</PopoverPortal>
</PopoverRoot>
</div>
</template>@import '../_colors/black-alpha.css';
@import '../_colors/mauve.css';
@import '../_colors/grass.css';
@scope (.akar-demo-Popover) {
/* reset */
button,
fieldset,
input {
all: unset;
}
.PopoverContent {
border-radius: 4px;
padding: 20px;
width: 260px;
background-color: white;
box-shadow:
hsl(206 22% 7% / 35%) 0px 10px 38px -10px,
hsl(206 22% 7% / 20%) 0px 10px 20px -15px;
animation-duration: 400ms;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
will-change: transform, opacity;
}
.PopoverContent:focus {
box-shadow:
hsl(206 22% 7% / 35%) 0px 10px 38px -10px,
hsl(206 22% 7% / 20%) 0px 10px 20px -15px,
0 0 0 2px var(--grass-7);
}
.PopoverContent[data-state='open'][data-side='top'] {
animation-name: slideDownAndFade;
}
.PopoverContent[data-state='open'][data-side='right'] {
animation-name: slideLeftAndFade;
}
.PopoverContent[data-state='open'][data-side='bottom'] {
animation-name: slideUpAndFade;
}
.PopoverContent[data-state='open'][data-side='left'] {
animation-name: slideRightAndFade;
}
.PopoverArrow {
fill: white;
}
.PopoverClose {
font-family: inherit;
border-radius: 100%;
height: 25px;
width: 25px;
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--grass-11);
position: absolute;
top: 5px;
right: 5px;
}
.PopoverClose:hover {
background-color: var(--grass-4);
}
.PopoverClose:focus {
box-shadow: 0 0 0 2px var(--grass-7);
}
.IconButton {
font-family: inherit;
border-radius: 100%;
height: 35px;
width: 35px;
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--grass-11);
background-color: white;
box-shadow: 0 2px 10px var(--black-a7);
}
.IconButton:hover {
background-color: var(--grass-3);
}
.IconButton:focus {
box-shadow: 0 0 0 2px black;
}
.Fieldset {
display: flex;
gap: 20px;
align-items: center;
}
.Label {
font-size: 13px;
color: var(--grass-11);
width: 75px;
}
.Input {
width: 100%;
display: inline-flex;
align-items: center;
justify-content: center;
flex: 1;
border-radius: 4px;
padding: 0 10px;
font-size: 13px;
line-height: 1;
color: var(--grass-11);
box-shadow: 0 0 0 1px var(--grass-7);
height: 25px;
}
.Input:focus {
box-shadow: 0 0 0 2px var(--grass-8);
}
.Text {
margin: 0;
color: var(--mauve-12);
font-size: 15px;
line-height: 19px;
font-weight: 500;
}
@keyframes slideUpAndFade {
from {
opacity: 0;
transform: translateY(2px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideRightAndFade {
from {
opacity: 0;
transform: translateX(-2px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideDownAndFade {
from {
opacity: 0;
transform: translateY(-2px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideLeftAndFade {
from {
opacity: 0;
transform: translateX(2px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
}Summary
The steps above outline briefly what's involved in using Akar in your application.
These components are low-level enough to give you control over how you want to wrap them. You're free to introduce your own high-level API to better suit the needs of your team and product.
In a few simple steps, we've implemented a fully accessible Popover component, without having to worry about many of its complexities.
- Adheres to WAI-ARIA design pattern.
- Can be controlled or uncontrolled.
- Customize side, alignment, offsets, collision handling.
- Optionally render a pointing arrow.
- Focus is fully managed and customizable.
- Dismissing and layering behavior is highly customizable.
Working with LLMs
Akar documentation is optimized for Large Language Models (LLMs) to help you get AI-powered assistance while working with our components.
LLM-Friendly Documentation
Our documentation includes a special LLM-friendly format that makes it easier for AI assistants to understand and provide accurate help with Akar components. This format:
- Removes visual elements and complex formatting that can confuse LLMs
- Structures content in a way that's optimized for text processing
- Includes comprehensive component information in a linear format
- Maintains all the essential technical details while being machine-readable
Accessing LLM Documentation
You can access the LLM-optimized version of our documentation at llms.txt. This file contains:
- Complete overview of all Akar components
- Detailed API documentation
- Usage examples and implementation patterns
- Accessibility guidelines
- Styling and customization options
Using LLMs with Akar
When working with LLMs like ChatGPT, Claude, or other AI assistants, you can:
- Reference the llms.txt file: Direct your AI assistant to the
/llms.txtfile for comprehensive context about Akar - Ask specific questions: Get help with implementation, styling, or accessibility features
- Generate code examples: Request custom implementations based on your specific needs
- Troubleshoot issues: Get assistance with common problems or edge cases
Example Prompts
Here are some example prompts you can use with LLMs:
"Using the Akar documentation at https://vinicunca.dev/raw/akar/overview.md, help me implement a custom Dialog component with form validation."
"Based on https://vinicunca.dev/raw/akar/components/select.md, show me how to create an accessible Select with custom styling."
"Refer to https://vinicunca.dev/.well-known/skills/akar/SKILL.md and explain keyboard navigation for Combobox."
By leveraging our LLM-optimized documentation, you can get more accurate and helpful responses from AI assistants when working with Akar components.