Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Tailwind Datatables Laravel Package

gorlabs/tailwind-datatables

Laravel package that integrates Yajra DataTables with a Tailwind CSS + Alpine.js UI. Supports server-side processing, search, pagination, sorting, buttons, and rich column customization. Publish config and optional CSS assets for easy theming.

View on GitHub
Deep Wiki
Context7

Laravel + Vue + Tailwind DataTables Kurulum Rehberi

Bu rehber, Laravel projesi oluşturma, Vue ve Inertia.js kurulumu, ayrıca gorlabs/tailwind-datatables paketinin kurulumu ve yapılandırmasını adım adım anlatmaktadır.


1. Laravel Projesi Oluşturma

İlk olarak yeni bir Laravel projesi oluşturun, lütfen prtoje geliştrimeye bu adımla başlayın her şeyin doğru kurulumla başlaması önemlidir:

laravel new gorlabs-datatable-vue && cd gorlabs-datatable-vue && composer require laravel/breeze --dev && touch resources/js/bootstrap.js && php artisan breeze:install vue &&  rm resources/js/app.ts && rm vite.config.ts && rm -rf resources/js/pages

package.json karmaşasını düzeltme laravel - vue stack kurulumunda gelen package json dosyası temiz ve düzdelidir, ancak breeze:instal vue komutunu çalıştırdığınız zaman bu scaffold maalesef mevcut düzeni bozmaktadır. zaten kurulum scriptimizle bu eklemenin verdiği zararların büyük bölümü gidelidi şimdi package.json dosyanızı temzilemeniz gerekiyor çünkü bu breeze:installa vue komutru tarafından kirletildi ve çakışmalara nedne olacaktır şu aşamada package.json dosyası şu şekilde olmalıdır

{
    "private": true,
    "type": "module",
    "scripts": {
        "build": "vite build",
        "build:ssr": "vite build && vite build --ssr",
        "dev": "vite",
        "format": "prettier --write resources/",
        "format:check": "prettier --check resources/",
        "lint": "eslint . --fix"
    },
    "devDependencies": {
        "[@eslint](https://github.com/eslint)/js": "^9.19.0",
        "[@tailwindcss](https://github.com/tailwindcss)/forms": "^0.5.3",
        "[@types](https://github.com/types)/node": "^22.13.5",
        "[@vue](https://github.com/vue)/eslint-config-typescript": "^14.3.0",
        "autoprefixer": "^10.4.12",
        "eslint": "^9.17.0",
        "eslint-config-prettier": "^10.0.1",
        "eslint-plugin-vue": "^9.32.0",
        "postcss": "^8.4.31",
        "prettier": "^3.4.2",
        "prettier-plugin-organize-imports": "^4.1.0",
        "prettier-plugin-tailwindcss": "^0.6.11",
        "typescript-eslint": "^8.23.0",
        "vue-tsc": "^2.2.4"
    },
    "dependencies": {
        "[@inertiajs](https://github.com/inertiajs)/vue3": "^2.0.0",
        "[@tailwindcss](https://github.com/tailwindcss)/vite": "^4.1.1",
        "[@vitejs](https://github.com/vitejs)/plugin-vue": "^5.2.1",
        "[@vueuse](https://github.com/vueuse)/core": "^12.8.2",
        "class-variance-authority": "^0.7.1",
        "clsx": "^2.1.1",
        "concurrently": "^9.0.1",
        "laravel-vite-plugin": "^1.0",
        "lucide-vue-next": "^0.468.0",
        "reka-ui": "^2.2.0",
        "tailwind-merge": "^3.2.0",
        "tailwindcss": "^4.1.1",
        "tw-animate-css": "^1.2.5",
        "typescript": "^5.2.2",
        "vite": "^6.2.0",
        "vue": "^3.5.13",
        "ziggy-js": "^2.4.2"
    } 
}
  1. Composer Paket Kurulumu
composer require gorlabs/tailwind-datatables

Paketleri yayımlayın:


composer update

php artisan vendor:publish --tag=tailwind-datatables-views
php artisan vendor:publish --tag=gorlabs-tailwind-datatables-config 
php artisan vendor:publish --tag=tailwind-datatables-css

Ardından, resources/js/app.js dosyasının içeriğini aşağıdaki gibi güncelleyin. Bu dosya zaten mevcut olmalıdır.


// resources/js/app.js
import '../css/app.css';
// ********************************************************************
// * DataTables ve İlgili Kütüphaneler (SADECE GLOBAL İHTİYAÇLAR)     *
// ********************************************************************

import jQuery from 'jquery';
window.jQuery = jQuery;
window.$ = jQuery;

import 'datatables.net';
import 'datatables.net-buttons';
import 'datatables.net-buttons/js/buttons.html5.js'; // HTML5 export butonları
import 'datatables.net-buttons/js/buttons.print.js'; // Print butonu
import 'datatables.net-buttons/js/buttons.colVis.js'; // Column visibility butonu
import 'datatables.net-responsive';



import JSZip from 'jszip';
import pdfMake from 'pdfmake/build/pdfmake';
import pdfFonts from 'pdfmake/build/vfs_fonts';
window.JSZip = JSZip;
window.pdfMake = pdfMake;
window.pdfMake.vfs = pdfFonts.vfs;

import Swal from 'sweetalert2';
window.Swal = Swal;

import dayjs from 'dayjs';
window.dayjs = dayjs;
import Alpine from 'alpinejs';

import { registerGorlabsDatatablesAlpineComponents } from '../../vendor/gorlabs/tailwind-datatables/resources/js/crud-datatable';


// ********************************************************************
// * Mevcut Inertia.js ve Vue başlatma kodları (DEĞİŞTİRME)            *
// ********************************************************************
import { createInertiaApp } from '[@inertiajs](https://github.com/inertiajs)/vue3';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import { createApp, h } from 'vue';
import { ZiggyVue } from 'ziggy-js';

const appName = import.meta.env.VITE_APP_NAME || 'Laravel';

createInertiaApp({
    title: (title) => `${title} - ${appName}`,
    resolve: (name) =>
        resolvePageComponent(
            `./Pages/${name}.vue`,
            import.meta.glob('./Pages/**/*.vue'),
        ),
    setup({ el, App, props, plugin }) {
        return createApp({ render: () => h(App, props) })
            .use(plugin)
            .use(ZiggyVue)
            .mount(el);
    },
    progress: {
        color: '#4B5563',
    },
});
// Yeni Eklenecek Kısım: Alpine.js'in yüklenmesini bekleyip bileşenleri kaydet
// Bu event listener, Alpine.js CDN'den yüklendiğinde ve hazır olduğunda tetiklenir.
registerGorlabsDatatablesAlpineComponents(Alpine); // Bileşenleri kaydet
Alpine.start();

postcss.config.js içeriğini güncelleyin

export default {
    plugins: {
        '[@tailwindcss](https://github.com/tailwindcss)/postcss': {},
        autoprefixer: {},
    },
};
  1. Vite Konfigürasyonları

vite.config.js dosyasının içeriğini aşağıdaki gibi güncelleyin. Bu dosya zaten mevcut olmalıdır.

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '[@vitejs](https://github.com/vitejs)/plugin-vue';
export default defineConfig({
    plugins: [
        laravel({
            input: [
                'resources/css/app.css',
                'resources/js/app.js'
            ],
            refresh: true,
        }),
        vue({
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
            },
        }),
    ],
    build: {
        minify: true, //  Minificaiton open
        sourcemap: true, // Hata ayıklama için sourcemap oluştur
    },
    server: {
        cors: true,
    },

});

X. resources/js/types/global.d.ts içeriğini güncelleyin

//resources/js/types/globals.d.ts
import { AppPageProps } from '@/types/index';
import type Swal from 'sweetalert2'; // type import kullan
import type dayjs from 'dayjs';     // type import kullan
import type Alpine from 'alpinejs';  // type import kullan
import type * as pdfMake from 'pdfmake/build/pdfmake'; // type import kullan
import type * as JSZip from 'jszip'; // type import kullan

// Extend ImportMeta interface for Vite...
declare module 'vite/client' {
    interface ImportMetaEnv {
        readonly VITE_APP_NAME: string;
        [key: string]: string | boolean | undefined;
    }

    interface ImportMeta {
        readonly env: ImportMetaEnv;
        readonly glob: <T>(pattern: string) => Record<string, () => Promise<T>>;
    }
}

declare module '[@inertiajs](https://github.com/inertiajs)/core' {
    interface PageProps extends InertiaPageProps, AppPageProps {}
}

declare module 'vue' {
    interface ComponentCustomProperties {
        $inertia: typeof Router;
        $page: Page;
        $headManager: ReturnType<typeof createHeadManager>;
    }
}

declare global {
    interface Window {
        GorlabsDatatables: {
            date: (format: string) => (data: any, type: string, row: any) => string;
            statusBadge: (publishedText: string, draftText: string) => (data: any, type: string, row: any) => string;
            actions: (updateUrlPrefix: string, deleteUrlPrefix: string) => (data: any, type: string, row: any) => string;
            // Diğer GorlabsDatatables metotlarını da buraya ekleyin
        };
        Swal: any; // SweetAlert2 için de benzer şekilde ekleyebilirsiniz
        openFormModal: (title: string, url: string, item: any | null) => void; // Global fonksiyon için de
    }
}

// ********************************************************************
// * Yeni Eklenecek Kısım: Global Window Objektif Tanımları             *
// ********************************************************************
declare global {
    interface Window {
        Swal: typeof Swal;
        dayjs: typeof dayjs;
        Alpine: typeof Alpine;
        pdfMake: typeof pdfMake;
        JSZip: typeof JSZip;
        jQuery: JQuery;
        $: JQuery;
        crudDataTable: (config: any) => any;
    }
}
  1. PHP Backend Dosyaları Migration Oluşturma Posts tablosunu oluşturmak için bir migration dosyası oluşturun ve içeriğini aşağıdakilerle değiştirin:
php artisan make:migration create_posts_table

Oluşan dosya yolu: database/migrations/YYYY_MM_DD_HHMMSS_create_posts_table.php (buradaki YYYY_MM_DD_HHMMSS kısmı tarih ve saate göre değişecektir). İçeriğini aşağıdaki gibi güncelleyin:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('content');
            $table->timestamp('published_at')->nullable(); // Yayım tarihi
            $table->boolean('is_published')->default(false); // Durum (yayınlandı mı?)
            $table->string('status')->default('draft'); // Örnek olarak eklendi
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('posts');
    }
};

Model Oluşturma Post modelini ve PostFactory.php yi oluşturun ve içeriklerini aşağıdakilerle değiştirin:

php artisan make:model Post -f

Oluşan dosya yolu: app/Models/Post.php. İçeriğini aşağıdaki gibi güncelleyin:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;

    protected $fillable = [
        'title',
        'content',
        'published_at',
        'is_published',
        'status',
    ];

    protected $casts = [
        'is_published' => 'boolean',
        'published_at' => 'datetime',
    ];
}

PostFactory.php içeriği aşağıdaki gib olmalı

<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * [@extends](https://github.com/extends) \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Post>
 */
class PostFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * [@return](https://github.com/return) array<string, mixed>
     */
    public function definition(): array
    {
        return [
            'title' => fake()->sentence(rand(3, 8)),
            'content' => fake()->paragraphs(rand(1, 3), true),
            'published_at' => fake()->optional(0.8)->dateTimeThisYear(), // %80 ihtimalle bir tarih verir
            'is_published' => fake()->boolean(90), // %90 ihtimalle true
            'status' => fake()->randomElement(['draft', 'published', 'archived']),
        ];
    }
}
php artisan make:seeder PostSeeder

PostSeeder.php içeriği

<?php

namespace Database\Seeders;

use App\Models\Post;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

class PostSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        // 50 adet sahte Post oluştur
        Post::factory()->count(50)->create();
    }
}

DatabaseSeeder.php içeriği

<?php

namespace Database\Seeders;

use App\Models\User;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Database\Factories\PostFactory;use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     */
    public function run(): void
    {
        // User::factory(10)->create();

        User::factory()->create([
            'name' => 'Test User',
            'email' => 'test@example.com',
        ]);
        $this->call([PostSeeder::class,]);
    }
}

DataTable Sınıfı Oluşturma PostsDataTable sınıfını oluşturun ve içeriğini aşağıdakilerle değiştirin:

php artisan datatable:make PostsDataTable --model=Post

Oluşan dosya yolu: app/DataTables/PostsDataTable.php. İçeriğini aşağıdaki gibi güncelleyin:

<?php

namespace App\DataTables;

use App\Models\Post;
use Illuminate\Database\Eloquent\Builder as QueryBuilder;
use Yajra\DataTables\EloquentDataTable;
use Yajra\DataTables\Html\Builder as HtmlBuilder;
use Yajra\DataTables\Html\Button;
use Yajra\DataTables\Html\Column;
use Yajra\DataTables\Services\DataTable;

class PostsDataTable extends DataTable
{
    public function query(Post $model): QueryBuilder
    {
        return $model->newQuery()->select('id', 'title', 'content', 'is_published', 'published_at', 'status', 'created_at', 'updated_at');
    }

    public function dataTable(QueryBuilder $query): EloquentDataTable
    {
        return (new EloquentDataTable($query))
            ->setRowId('id')
            ->addColumn('select_checkbox', function(Post $post) {
                return '';
            })
            ->addColumn('actions', function(Post $post) {
                return '';
            })
            ->editColumn('is_published', function(Post $post) {
                return $post->is_published ? 1 : 0;
            })
            ->editColumn('published_at', function(Post $post) {
                return $post->published_at ? $post->published_at->format('Y-m-d H:i:s') : null;
            })
            ->editColumn('title', function(Post $post) {
                $title = $post->title;
                if (strlen($title) > 24) {
                    return substr($title, 0, 24) . ' ...';
                }
                return $title;
            })
            ->editColumn('content', function(Post $post) {
                $content = $post->content;
                if (strlen($content) > 34) {
                    return substr($content, 0, 34) . ' ...';
                }
                return $content;
            });
    }

    public function html(): HtmlBuilder
    {
        return $this->builder()
            ->setTableId('posts-table')
            ->columns($this->getColumns())
            ->minifiedAjax()
            ->orderBy(1)
            ->select(false)
            ->buttons([
                Button::make('create'),
                Button::make('export'),
                Button::make('print'),
                Button::make('reset'),
                Button::make('reload')
            ]);
    }

    public function getColumns(): array
    {
        $columns = [
            Column::computed('select_checkbox')
                ->title('<input type="checkbox" id="select-all-checkbox" class="rounded border-gray-300 text-indigo-600 shadow-sm focus:ring-indigo-500">')
                ->exportable(false)
                ->printable(false)
                ->width(10)
                ->addClass('text-center')
                ->orderable(false)
                ->searchable(false)
                ->footer('')
                ->responsivePriority(1),
            Column::make('id')->responsivePriority(2),
            Column::make('title')->responsivePriority(3),
            Column::make('content')->responsivePriority(5),
            Column::make('published_at')
                ->title('Published At')
                ->width(150)
                ->responsivePriority(4),
            Column::make('is_published')
                ->title('Published')
                ->width(100)
                ->responsivePriority(4),
            Column::make('status')->responsivePriority(4),
        ];

        $columns[] = Column::computed('actions')
            ->title('ACTIONS')
            ->exportable(false)
            ->printable(false)
            ->width(120)
            ->addClass('text-center')
            ->orderable(false)
            ->searchable(false)
            ->footer('')
            ->responsivePriority(1);

        return $columns;
    }

    protected function filename(): string
    {
        return 'Posts_' . date('YmdHis');
    }
}

Controller Oluşturma PostController sınıfını oluşturun ve içeriğini aşağıdakilerle değiştirin:

php artisan make:controller PostController

Oluşan dosya yolu: app/Http/Controllers/PostController.php. İçeriğini aşağıdaki gibi güncelleyin:

<?php

namespace App\Http\Controllers;

use App\DataTables\PostsDataTable;
use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Inertia\Inertia;

class PostController extends Controller
{
    public function index(PostsDataTable $postsDataTable)
    {
        $columns = $postsDataTable->getColumns();

        $formattedColumns = collect($columns)->map(function ($column) {
            return [
                'data' => $column->data,
                'name' => $column->name,
                'title' => $column->title,
                'orderable' => $column->orderable,
                'searchable' => $column->searchable,
                'className' => $column->className ?? '',
            ];
        })->toArray();

        return Inertia::render('Posts/Index', [
            'columns' => $formattedColumns,
        ]);
    }

    public function ajaxData(PostsDataTable $dataTable)
    {
        Log::info('DataTables AJAX isteği parametreleri:', request()->all());
        return $dataTable->dataTable($dataTable->query(new Post()))->make(true);
    }

    public function create()
    {
        return view('tailwind-datatables::datatables.form', ['post' => new Post()]);
    }

    public function store(Request $request)
    {
        $request->validate([
            'title' => 'required|string|max:255',
            'content' => 'nullable|string',
            'is_published' => 'nullable|boolean',
            'published_at' => 'nullable|date',
        ]);

        $data = $request->except(['published_at']);
        $data['published_at'] = $request->input('published_at') ? now()->parse($request->input('published_at')) : null;
        $data['is_published'] = (bool) $request->input('is_published', 0);

        $post = Post::create($data);

        return response()->json(['success' => 'Post başarıyla oluşturuldu.', 'post' => $post]);
    }

    public function edit(Post $post)
    {
        $post->published_at_formatted = $post->published_at ? $post->published_at->format('Y-m-d\TH:i') : '';

        return view('tailwind-datatables::datatables.form', compact('post'));
    }

    public function update(Request $request, Post $post)
    {
        $request->validate([
            'title' => 'required|string|max:255',
            'content' => 'nullable|string',
            'is_published' => 'boolean|nullable',
            'published_at' => 'nullable|date',
        ]);

        $data = $request->except(['published_at']);
        $data['is_published'] = (bool) $request->input('is_published', 0);
        $data['published_at'] = $request->input('published_at') ? now()->parse($request->input('published_at')) : null;

        $post->update($data);

        return response()->json(['success' => 'Post başarıyla güncellendi.', 'post' => $post]);
    }

    public function destroy(Post $post)
    {
        try {
            $post->delete();
            return response()->json(['success' => 'Post başarıyla silindi.']);
        } catch (\Exception $e) {
            Log::error('Post silinirken hata oluştu: ' . $e->getMessage(), ['post_id' => $post->id]);
            return response()->json(['error' => 'Post silinirken bir hata oluştu.'], 500);
        }
    }
}
  1. Vue Bileşeni resources/js/Pages/Posts/Index.vue dosyasını oluşturun ve içeriğini aşağıdakilerle değiştirin:
mkdir -p resources/js/Pages/Posts
touch resources/js/Pages/Posts/Index.vue

Oluşan dosya yolu: resources/js/Pages/Posts/Index.vue. İçeriğini aşağıdaki gibi güncelleyin:

Kod snippet'i

<script setup lang="ts">
    import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';

    import { Head } from '[@inertiajs](https://github.com/inertiajs)/vue3';

    import { onMounted, ref } from 'vue';

    // Backend'den gelen columns prop'unu tanımla

    const props = defineProps<{
        columns: Array<{
            data: string;

            name: string;

            title: string;

            orderable: boolean;

            searchable: boolean;

            className?: string; // className opsiyonel olabilir
        }>;
    }>();

    console.log('Props Columns:', props.columns);

    // DataTables'ın HTML yapısı için bir ref oluştur

    const dataTableContainer = ref<HTMLElement | null>(null);

    // crudDataTable config'i props'tan gelen kolonları kullanarak tanımlıyoruz.

    const datatableConfig = {
        datatableId: 'posts-table',

        ajaxUrl: route('posts.data'),

        columns: props.columns, // Kolonları props'tan alıyoruz!

        perPage: 10,

        perPageSelect: [10, 25, 50, 100, -1],

        addNewButtonText: 'Add New Post',

        addEditUrl: route('posts.create'),

        updateUrlPrefix: route('posts.update', ''),

        deleteUrlPrefix: route('posts.destroy', ''),

        initialFormState: {},

        responsive: true, // Responsive özelliği burada true olarak ayarlı
    };

    // DataTables instance'ını saklamak için bir ref

    const dataTableInstance = ref<any>(null);

    const $ = window.$ as any;

    onMounted(() => {
        // jQuery ve DataTabl...
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
nasirkhan/laravel-sharekit
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony